您的位置:首页 > 科技 > 能源 > 佛山网站设计网站公司_seo推广淘客_百度关键词排名神器_如何优化网站推广

佛山网站设计网站公司_seo推广淘客_百度关键词排名神器_如何优化网站推广

2025/4/5 6:32:33 来源:https://blog.csdn.net/weixin_52242569/article/details/146397105  浏览:    关键词:佛山网站设计网站公司_seo推广淘客_百度关键词排名神器_如何优化网站推广
佛山网站设计网站公司_seo推广淘客_百度关键词排名神器_如何优化网站推广

线程安全的单例模式与生产者消费者问题

1. 线程安全的单例模式

单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。在多线程环境下,单例模式的实现需要考虑线程安全问题。以下是使用双重检查锁定(Double-Checked Locking)实现的线程安全单例模式:

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;}
}

关键点:

  • volatile 关键字确保 instance 变量的可见性,防止指令重排序。
  • 双重检查锁定(Double-Checked Locking)减少同步开销,只有在第一次创建实例时才进行同步。

2. 使用 ReentrantLock + Condition + CountDownLatch + ThreadPool 实现生产者消费者问题

生产者消费者问题是多线程编程中的经典问题,涉及生产者和消费者之间的同步。以下是使用 ReentrantLockConditionCountDownLatch 和线程池实现的生产者消费者模型:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class ProducerConsumerWithThreadPool {private static final int CAPACITY = 10; // 缓冲区容量private static final int PRODUCER_COUNT = 3; // 生产者数量private static final int CONSUMER_COUNT = 5; // 消费者数量private static final int TOTAL_DATA = 30; // 总共生产的数据量private static Queue<Integer> queue = new LinkedList<>();private static Lock lock = new ReentrantLock();private static Condition notFull = lock.newCondition();private static Condition notEmpty = lock.newCondition();private static CountDownLatch producerLatch = new CountDownLatch(PRODUCER_COUNT);private static CountDownLatch consumerLatch = new CountDownLatch(CONSUMER_COUNT);private static int producedCount = 0; // 已生产的数据量private static int consumedCount = 0; // 已消费的数据量public static void main(String[] args) throws InterruptedException {// 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(PRODUCER_COUNT + CONSUMER_COUNT);// 提交生产者任务for (int i = 0; i < PRODUCER_COUNT; i++) {executorService.submit(new Producer(i + 1));}// 提交消费者任务for (int i = 0; i < CONSUMER_COUNT; i++) {executorService.submit(new Consumer(i + 1));}// 等待所有生产者线程完成producerLatch.await();// 等待所有消费者线程完成consumerLatch.await();// 关闭线程池executorService.shutdown();System.out.println("测试结束信息");}static class Producer implements Runnable {private int id;public Producer(int id) {this.id = id;}@Overridepublic void run() {try {while (true) {lock.lock();try {// 如果已经生产了足够的数据,退出if (producedCount >= TOTAL_DATA) {break;}while (queue.size() == CAPACITY) {notFull.await(); // 等待缓冲区不满}// 生产数据int data = ++producedCount;queue.offer(data);System.out.println("生产者 " + id + " 生产了数据: " + data);notEmpty.signal(); // 通知消费者可以消费} finally {lock.unlock();}Thread.sleep(100); // 模拟生产耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {producerLatch.countDown(); // 生产者线程结束}}}static class Consumer implements Runnable {private int id;public Consumer(int id) {this.id = id;}@Overridepublic void run() {try {while (true) {lock.lock();try {// 如果已经消费了所有数据,退出if (consumedCount >= TOTAL_DATA) {break;}while (queue.isEmpty()) {if (producedCount >= TOTAL_DATA) {// 如果生产者已经结束且队列为空,则消费者线程退出return;}notEmpty.await(); // 等待缓冲区不空}// 消费数据int data = queue.poll();consumedCount++;System.out.println("消费者 " + id + " 消费了数据: " + data);notFull.signal(); // 通知生产者可以生产} finally {lock.unlock();}Thread.sleep(200); // 模拟消费耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {consumerLatch.countDown(); // 消费者线程结束}}}
}

关键点:

  • ReentrantLockCondition 用于线程间的同步。
  • CountDownLatch 用于等待所有生产者和消费者线程完成任务。
  • 线程池管理生产者和消费者线程。

3. 使用 BlockingQueue 实现生产者消费者问题

BlockingQueue 是 Java 并发包中的一个接口,提供了线程安全的队列操作。以下是使用 BlockingQueue 实现的生产者消费者模型:

package ProducerConsumer;import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;public class test {private static final int PRODUCER_COUNT = 3; // 生产者数量private static final int CONSUMER_COUNT = 5; // 消费者数量private static final int TOTAL_DATA = 30; // 总共生产的数据量private static BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10); // 缓冲区容量为 10private static CountDownLatch productLatch = new CountDownLatch(PRODUCER_COUNT);private static CountDownLatch consumeLatch = new CountDownLatch(CONSUMER_COUNT);private static AtomicInteger producedCount = new AtomicInteger(1); // 已生产的数据量private static final Integer END_MARKER = -1; // 结束标记public static void main(String[] args) throws InterruptedException {// 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(PRODUCER_COUNT + CONSUMER_COUNT);// 提交生产者任务for (int i = 0; i < PRODUCER_COUNT; i++) {executorService.submit(new Producer(i + 1));}// 提交消费者任务for (int i = 0; i < CONSUMER_COUNT; i++) {executorService.submit(new Consumer(i + 1));}// 等待所有生产者线程完成productLatch.await();System.out.println("所有生产者已完成生产");// 向队列中放入结束标记,通知消费者线程退出for (int i = 0; i < CONSUMER_COUNT; i++) {queue.put(END_MARKER);System.out.println("向队列中添加结束标记");}// 等待所有消费者线程完成consumeLatch.await();System.out.println("所有消费者已完成消费");// 关闭线程池executorService.shutdown();executorService.awaitTermination(10, TimeUnit.SECONDS); // 等待线程池中的任务完成System.out.println("测试结束信息");}static class Producer implements Runnable {private int id;public Producer(int id) {this.id = id;}@Overridepublic void run() {try {while (producedCount.get() <= TOTAL_DATA) {int data = producedCount.getAndIncrement();if (data > TOTAL_DATA) {producedCount.decrementAndGet(); // 回滚,避免超出范围break;}queue.put(data);System.out.println("生产者 " + id + " 生产了数据: " + data + ",当前队列大小: " + queue.size());Thread.sleep(200); // 模拟生产耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("生产者 " + id + " 线程被中断");} finally {productLatch.countDown();}}}static class Consumer implements Runnable {int id;public Consumer(int id) {this.id = id;}@Overridepublic void run() {try {while (true) {int data = queue.take();if (data == END_MARKER) {break;}System.out.println("消费者 " + id + " 消费了数据: " + data + ",当前队列大小: " + queue.size());Thread.sleep(300); // 模拟消费耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("消费者 " + id + " 线程被中断");} finally {consumeLatch.countDown(); // 消费者线程结束}}}
}

关键点:

  • BlockingQueue 提供了线程安全的队列操作,简化了同步逻辑。
  • 使用 END_MARKER 作为结束标记,通知消费者线程退出。
  • CountDownLatch 用于等待所有生产者和消费者线程完成任务。

总结

本文介绍了线程安全的单例模式以及两种实现生产者消费者问题的方法。第一种方法使用 ReentrantLockCondition 实现,第二种方法使用 BlockingQueue 实现。两种方法各有优缺点,选择哪种方法取决于具体的应用场景和需求。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com