Bootstrap

【Java多线程】8 Java 中的并发设计模式

接下来我们学习第八部分:Java 中的并发设计模式


8. Java 中的并发设计模式

在并发编程中,设计模式可以帮助我们更好地组织代码,提高可读性和可维护性。以下是一些常见的并发设计模式及其在 Java 中的实现。

8.1 生产者-消费者模式

生产者-消费者模式用于解决生产者生成数据和消费者处理数据之间的协调问题。通常,生产者会把数据放入一个共享队列中,而消费者则从这个队列中取出数据进行处理。Java 中可以使用 BlockingQueue 来实现这一模式。

示例代码
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

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

    public static void main(String[] args) {
        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    queue.put(i); // 将生产的数据放入队列
                    System.out.println("Produced: " + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    int value = queue.take(); // 从队列中取出数据
                    System.out.println("Consumed: " + value);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

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

        try {
            producer.join();
            consumer.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

8.2 单例模式

在多线程环境中,单例模式确保一个类只有一个实例,并提供一个全局访问点。为了防止多线程环境下的实例化问题,通常会使用双重检查锁定。

示例代码
public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {} // 私有构造函数

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(); // 创建实例
                }
            }
        }
        return instance;
    }
}

8.3 读写锁模式

在并发环境中,如果有大量线程只读数据而很少写入,可以使用读写锁模式来提高性能。Java 提供了 ReentrantReadWriteLock 来实现这一模式。

示例代码
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private String data;

    public void write(String value) {
        lock.writeLock().lock(); // 获取写锁
        try {
            this.data = value;
            System.out.println("Written: " + value);
        } finally {
            lock.writeLock().unlock(); // 释放写锁
        }
    }

    public String read() {
        lock.readLock().lock(); // 获取读锁
        try {
            System.out.println("Read: " + data);
            return data;
        } finally {
            lock.readLock().unlock(); // 释放读锁
        }
    }
}

8.4 Future 和 CompletableFuture

FutureCompletableFuture 提供了异步编程的能力,允许我们在任务完成时执行某些操作,而不需要阻塞主线程。

示例代码(Future)
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        
        Future<Integer> future = executor.submit(new Callable<Integer>() {
            @Override
            public Integer call() {
                // 模拟计算
                Thread.sleep(2000);
                return 42;
            }
        });
        
        try {
            // 在计算未完成时可以做其他事情
            System.out.println("Doing other work...");
            Integer result = future.get(); // 阻塞直到获取结果
            System.out.println("Result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}
示例代码(CompletableFuture)
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // 模拟计算
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 42;
        });

        // 在计算未完成时可以做其他事情
        future.thenAccept(result -> System.out.println("Result: " + result));

        System.out.println("Doing other work...");
        
        // 等待异步操作完成
        future.join();
    }
}

8.5 任务调度模式

任务调度模式允许我们定期执行某些任务。可以使用 ScheduledExecutorService 实现定时任务。

示例代码
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledTaskExample {
    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        
        Runnable task = () -> System.out.println("Scheduled task executed at: " + System.currentTimeMillis());
        
        // 延迟 2 秒执行任务
        scheduler.schedule(task, 2, TimeUnit.SECONDS);
        
        // 每 5 秒执行一次任务
        scheduler.scheduleAtFixedRate(task, 0, 5, TimeUnit.SECONDS);
        
        // 运行一段时间后关闭调度器
        try {
            Thread.sleep(20000); // 等待 20 秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            scheduler.shutdown();
        }
    }
}

总结

在并发编程中,使用设计模式可以帮助我们更好地组织代码,提升可读性和可维护性。了解这些并发设计模式及其在 Java 中的实现,将使我们能够更高效地编写并发程序。

下一步,我们将学习 Java 的并发性能优化,包括如何优化并发程序的性能,提高系统的响应速度和吞吐量。

;