Java并发编程从入门到进阶 多场景实战

88 阅读4分钟

Java并发编程从入门到进阶 多场景实战

Java并发编程从入门到进阶 多场景实战

Java并发编程是现代软件开发中的重要技能,特别是在高性能和高可用性要求的系统中。以下是从入门到进阶的Java并发编程知识,结合多场景实战进行详细介绍:

一、Java并发编程基础知识

  1. 并发与并行的概念
  2. 并发:指在同一时间段内,可以有多个执行路径在运行,但不一定是同时执行。在Java中,这通常是通过多线程实现的。
  3. 并行:指多个任务在同一时刻同时执行,这需要多核或多处理器系统。
  4. 线程的创建
  5. Java中,线程是程序执行的基本单位。一个Java应用程序至少有一个主线程(main线程)。
  6. 创建新线程有两种主要方式:继承Thread类、实现Runnable接口。
  7. 线程的生命周期
  8. 新建(New):线程被创建但尚未启动。
  9. 就绪(Runnable):线程已启动,等待CPU分配时间片。
  10. 运行(Running):线程正在执行。
  11. 阻塞(Blocked):线程因为某种原因被阻塞,等待资源。
  12. 死亡(Dead):线程执行完成,资源被释放。

二、Java并发编程进阶知识

  1. 线程池
  2. Java提供了多种并发工具,主要集中在java.util.concurrent包中。
  3. Executor框架提供了更高层次的线程管理,简化了线程的创建和管理。
  4. 常用的线程池有FixedThreadPool、CachedThreadPool等。
  5. 线程安全的数据结构
  6. Java提供了多种线程安全的数据结构,如ConcurrentHashMap、CopyOnWriteArrayList等。
  7. 这些数据结构在多线程环境下能够保证数据的一致性。
  8. 锁机制
  9. Java提供了多种锁机制,最常用的是ReentrantLock。
  10. 锁可以用于保护共享资源,以避免数据竞争。

三、多场景实战

  1. 生产者-消费者模型
  2. 生产者线程负责生产数据,而消费者线程负责消费数据。
  3. 可以使用BlockingQueue来实现这一模型。
  4. 示例代码:

Java

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ProducerConsumerExample {
    private static final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

    public static void main(String[] args) {
        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 20; i++) {
                    queue.put(i);
                    System.out.println("Produced: " + i);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 20; i++) {
                    Integer value = queue.take();
                    System.out.println("Consumed: " + value);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

2. 线程安全的计数器 3. 在一些场景中,需要一个线程安全的计数器。 4. 可以使用AtomicInteger来实现。 5. Phaser控制并发任务的多个阶段 6. Phaser是一个灵活的同步屏障,可以用来控制并发任务的多个阶段。 7. 它比CyclicBarrier和CountDownLatch更加灵活。 8. 示例代码:

Java

import java.util.concurrent.Phaser;

public class PhaserExample {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(1); // 注册主线程
        for (int i = 0; i < 3; i++) {
            phaser.register(); // 动态注册参与者
            new Thread(new Task(phaser)).start();
        }
        phaser.arriveAndDeregister(); // 主线程到达并注销
        // 等待所有任务完成
        phaser.awaitAdvance(phaser.getPhase());
        System.out.println("All tasks completed.");
    }
}

class Task implements Runnable {
    private Phaser phaser;

    Task(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        phaser.arriveAndAwaitAdvance(); // 第一个阶段
        System.out.println(Thread.currentThread().getName() + " completed phase 1");
        phaser.arriveAndAwaitAdvance(); // 第二个阶段
        System.out.println(Thread.currentThread().getName() + " completed phase 2");
        phaser.arriveAndDeregister(); // 完成所有阶段并注销
    }
}

4. Semaphore控制并发访问 5. Semaphore是一个计数信号量,用于控制对共享资源的并发访问。 6. 它可以限制同时访问某个资源的线程数量。 7. 示例代码:

Java

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问
        for (int i = 0; i < 10; i++) {
            new Thread(new Worker(semaphore)).start();
        }
    }
}

class Worker implements Runnable {
    private Semaphore semaphore;

    Worker(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " acquired semaphore");
            Thread.sleep(2000); // 模拟工作
            System.out.println(Thread.currentThread().getName() + " released semaphore");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }
}

5. Exchanger线程间数据交换 6. Exchanger是一个用于在两个线程之间交换数据的同步点。 7. 每个线程在同步点上等待,直到另一个线程到达,然后两个线程交换数据。 8. 示例代码:

Java

import java.util.concurrent.Exchanger;

public class ExchangerExample {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        new Thread(new Producer(exchanger)).start();
        new Thread(new Consumer(exchanger)).start();
    }
}

class Producer implements Runnable {
    private Exchanger<String> exchanger;

    Producer(Exchanger<String> exchanger) {
        this.exchanger = exchanger;
    }

    @Override
    public void run() {
        try {
            String data = "Data from Producer";
            System.out.println("Producer is producing data: " + data);
            String response = exchanger.exchange(data);
            System.out.println("Producer received response: " + response);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Consumer implements Runnable {
    private Exchanger<String> exchanger;

    Consumer(Exchanger<String> exchanger) {
        this.exchanger = exchanger;
    }

    @Override
    public void run() {
        try {
            String data = "Data from Consumer";
            System.out.println("Consumer is producing data: " + data);
            String response = exchanger.exchange(data);
            System.out.println("Consumer received response: " + response);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

四、总结

Java并发编程是一个复杂而强大的领域,通过掌握基础知识和进阶技巧,并结合多场景实战,可以更好地利用Java提供的并发编程工具和库来实现高效、可扩展和可靠的系统。