JUC并发编程(四)常见模式

目录

一 同步与协调模式

 1 保护性暂停模式

 2 顺序控制模式

 3 生产者消费者模式

4 Balking模式(犹豫模式)

二 线程管理/生命周期模式

1 两阶段终止模式


一 同步与协调模式

 1 保护性暂停模式

 一个线程需要等待另一个线程提供特定条件(通常是某个结果)满足后才能继续执行。

Guarded Suspension 保护性暂停是一种节点的多线程设计模式,用于在条件不满足时暂停线程执行,直到条件满足后在继续执行。(线程不满足等待条件,手动实现主动等待)

代码实现:

package day01.mysynchronized;import java.util.ArrayList;public class example6 {public static void main(String[] args) {GuardObject<ArrayList<Integer>> guardObject = new GuardObject<>();// 线程1等待线程2的结果new Thread(() -> {//  等待结果System.out.println("t1线程开始执行... 等待结果");ArrayList<Integer> result = guardObject.get();result.forEach(System.out::println);}, "t1").start();new Thread(() -> {System.out.println("t2线程开始执行...");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}ArrayList<Integer> objects = new ArrayList<>();objects.add(1);objects.add(2);guardObject.complete(objects);}, "t2").start();}
}class GuardObject<T> {private T response;public T get() {synchronized (this) {while (response == null) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}return response;}}public void complete(T response) {synchronized (this) {this.response = response;this.notifyAll();}}
}

更完善的:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;public class Example7 {public static void main(String[] args) {GuardObject<List<Integer>> guardObject = new GuardObject<>();// 线程1等待线程2的结果Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + "开始执行... 等待结果");try {// 设置5秒超时List<Integer> result = guardObject.get(5000);System.out.println(Thread.currentThread().getName() + "收到结果:");result.forEach(System.out::println);} catch (TimeoutException e) {System.out.println(Thread.currentThread().getName() + "等待结果超时");} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "被中断");}}, "t1");Thread t2 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + "开始执行...");try {// 模拟耗时操作Thread.sleep(3000);// 创建结果List<Integer> objects = new ArrayList<>();objects.add(1);objects.add(2);// 设置结果guardObject.complete(objects);System.out.println(Thread.currentThread().getName() + "已发送结果");} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "被中断");}}, "t2");t1.start();t2.start();// 确保主线程等待子线程完成try {t1.join();t2.join();} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("所有线程执行完成");}
}/*** 增强版保护对象类* @param <T> 结果类型*/
class GuardObject<T> {private T response;private boolean done = false; // 完成状态标志/*** 获取结果(无限等待)* @return 结果对象* @throws InterruptedException 如果等待时被中断*/public T get() throws InterruptedException, TimeoutException {return get(0);}/*** 获取结果(带超时)* @param timeout 超时时间(毫秒),0表示无限等待* @return 结果对象* @throws InterruptedException 如果等待时被中断* @throws TimeoutException 如果超过指定的超时时间*/public T get(long timeout) throws InterruptedException, TimeoutException {synchronized (this) {long start = System.currentTimeMillis();long remaining = timeout;while (!done) {if (timeout > 0 && remaining <= 0) {throw new TimeoutException("等待结果超时");}if (timeout == 0) {this.wait();} else {this.wait(remaining);remaining = timeout - (System.currentTimeMillis() - start);}}return response;}}/*** 设置结果* @param response 结果对象* @throws IllegalStateException 如果结果已被设置*/public void complete(T response) {synchronized (this) {if (done) {throw new IllegalStateException("结果已被设置");}this.response = response;this.done = true;this.notifyAll();}}
}

一个使用等待通知机制的例子

信箱类:借助HashMap用于管理收信人id与对应的异步结果对象GuardObject

收信人:借助信箱类的管理,设置对应的id与新建异步结果对象,接着调用对应的get进行等待。

邮递员:传递收件人的id,并设置对应的content,借助信箱类根据收件人id得到对应的GuardObject异步结果对象,调用compete通知(将content传递)。

异步结果对象:两个方法,get/compete一个等待,一个通知,实现多线程的保护性暂停模式。

1 收信人

在收信人当中需要内置变量信箱,在初始化创建时就需要对应调用创建信箱的方法,然后重写run方法,因为我们需要实现的是每创建一个收信人就需要新建一个线程执行业务代码,run方法当中使用get进行等待,若邮递员发送通知之后再将结果接收,接收成功之后还需从信箱当中移除。

/*** 模拟收信人*/
class People extends Thread {private final GuardObject<String> guardObject;public People() {super("People-" + System.currentTimeMillis());this.guardObject = MailBox.createGuardObject();}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "开始收信...");try {// 等待信件,带超时String response = guardObject.get(5000);System.out.println(Thread.currentThread().getName() + "收到信:" + response);} catch (TimeoutException e) {System.out.println(Thread.currentThread().getName() + "收信超时");} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "收信被中断");Thread.currentThread().interrupt(); // 恢复中断状态} finally {// 确保从MailBox中移除GuardObjectMailBox.removeGuardObject(guardObject.getId());}}
}

2 邮递员

邮递员需要内置两个成员变量,一个是收信人的id用来获取寻找对应的收信人,同时也是开启新的线程继承Thread类重写run方法,首先获取收信人的对象,调用compete方法通知对应的收信人

/*** 邮递员类*/
class PostMan extends Thread {private final int id;private final String content;public PostMan(int id, String content) {super("PostMan-" + id);this.id = id;this.content = content;}@Overridepublic void run() {GuardObject<String> guardObject = MailBox.getGuardObject(id);if (guardObject == null) {System.out.println(Thread.currentThread().getName() + "错误:收信人不存在");return;}System.out.println(Thread.currentThread().getName() + "开始发送信件...");try {// 模拟投递延迟Thread.sleep(1000 + (int)(Math.random() * 2000));// 发送信件guardObject.complete(content);System.out.println(Thread.currentThread().getName() + "已发送信件");} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "发送被中断");Thread.currentThread().interrupt(); // 恢复中断状态} catch (IllegalStateException e) {System.out.println(Thread.currentThread().getName() + "错误:" + e.getMessage());}}
}

3 信箱类

信箱当中维护的是一个HashMap集合,id存储收件人信息,id,GuardObject<String>对象

/*** 用于管理多个 GuardObject 的信箱类*/
class MailBox {private static final AtomicInteger idGenerator = new AtomicInteger(1);private static final Map<Integer, GuardObject<?>> map = new ConcurrentHashMap<>();/*** 创建并返回一个泛型 GuardObject*/public static <T> GuardObject<T> createGuardObject() {int id = idGenerator.getAndIncrement();GuardObject<T> guardObject = new GuardObject<>(id);map.put(id, guardObject);return guardObject;}/*** 获取所有 GuardObject 的 ID*/public static Set<Integer> getGuardObjectIds() {return map.keySet();}/*** 根据id获取GuardObject*/@SuppressWarnings("unchecked")public static <T> GuardObject<T> getGuardObject(int id) {return (GuardObject<T>) map.get(id);}/*** 移除GuardObject*/public static void removeGuardObject(int id) {map.remove(id);}
}

4 保护对象

这里同时也会根据id维护独立的GuardObject对象,里面实现了get与compete的逻辑代码

/*** 增强版保护对象类*/
class GuardObject<T> {private T response;private boolean done = false;private final int id;public GuardObject(int id) {this.id = id;}public int getId() {return id;}/*** 获取结果(带超时)*/public T get(long timeout) throws InterruptedException, TimeoutException {synchronized (this) {long start = System.currentTimeMillis();long remaining = timeout;while (!done) {if (timeout > 0 && remaining <= 0) {throw new TimeoutException("等待结果超时");}if (timeout == 0) {this.wait();} else {this.wait(remaining);remaining = timeout - (System.currentTimeMillis() - start);}}return response;}}/*** 设置结果*/public void complete(T response) {synchronized (this) {if (done) {throw new IllegalStateException("结果已被设置");}this.response = response;this.done = true;this.notifyAll();}}

完整代码

package day01.mysynchronized;import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;public class Example7 {public static void main(String[] args) throws InterruptedException {// 创建多个收信人for (int i = 0; i < 3; i++) {new People().start();}// 等待收信人创建GuardObjectThread.sleep(1000);// 获取所有等待收信的IDSet<Integer> ids = MailBox.getGuardObjectIds();// 为每个收信人创建邮递员int mailCount = 1;for (int id : ids) {new PostMan(id, "信件内容" + mailCount++).start();}}
}/*** 模拟收信人*/
class People extends Thread {private final GuardObject<String> guardObject;public People() {super("People-" + System.currentTimeMillis());this.guardObject = MailBox.createGuardObject();}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "开始收信...");try {// 等待信件,带超时String response = guardObject.get(5000);System.out.println(Thread.currentThread().getName() + "收到信:" + response);} catch (TimeoutException e) {System.out.println(Thread.currentThread().getName() + "收信超时");} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "收信被中断");Thread.currentThread().interrupt(); // 恢复中断状态} finally {// 确保从MailBox中移除GuardObjectMailBox.removeGuardObject(guardObject.getId());}}
}/*** 邮递员类*/
class PostMan extends Thread {private final int id;private final String content;public PostMan(int id, String content) {super("PostMan-" + id);this.id = id;this.content = content;}@Overridepublic void run() {GuardObject<String> guardObject = MailBox.getGuardObject(id);if (guardObject == null) {System.out.println(Thread.currentThread().getName() + "错误:收信人不存在");return;}System.out.println(Thread.currentThread().getName() + "开始发送信件...");try {// 模拟投递延迟Thread.sleep(1000 + (int)(Math.random() * 2000));// 发送信件guardObject.complete(content);System.out.println(Thread.currentThread().getName() + "已发送信件");} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "发送被中断");Thread.currentThread().interrupt(); // 恢复中断状态} catch (IllegalStateException e) {System.out.println(Thread.currentThread().getName() + "错误:" + e.getMessage());}}
}/*** 用于管理多个 GuardObject 的信箱类*/
class MailBox {private static final AtomicInteger idGenerator = new AtomicInteger(1);private static final Map<Integer, GuardObject<?>> map = new ConcurrentHashMap<>();/*** 创建并返回一个泛型 GuardObject*/public static <T> GuardObject<T> createGuardObject() {int id = idGenerator.getAndIncrement();GuardObject<T> guardObject = new GuardObject<>(id);map.put(id, guardObject);return guardObject;}/*** 获取所有 GuardObject 的 ID*/public static Set<Integer> getGuardObjectIds() {return map.keySet();}/*** 根据id获取GuardObject*/@SuppressWarnings("unchecked")public static <T> GuardObject<T> getGuardObject(int id) {return (GuardObject<T>) map.get(id);}/*** 移除GuardObject*/public static void removeGuardObject(int id) {map.remove(id);}
}/*** 增强版保护对象类*/
class GuardObject<T> {private T response;private boolean done = false;private final int id;public GuardObject(int id) {this.id = id;}public int getId() {return id;}/*** 获取结果(带超时)*/public T get(long timeout) throws InterruptedException, TimeoutException {synchronized (this) {long start = System.currentTimeMillis();long remaining = timeout;while (!done) {if (timeout > 0 && remaining <= 0) {throw new TimeoutException("等待结果超时");}if (timeout == 0) {this.wait();} else {this.wait(remaining);remaining = timeout - (System.currentTimeMillis() - start);}}return response;}}/*** 设置结果*/public void complete(T response) {synchronized (this) {if (done) {throw new IllegalStateException("结果已被设置");}this.response = response;this.done = true;this.notifyAll();}}
}

结果展示

 2 顺序控制模式

顺序控制是同步模式中的一种重要控制方式,它确保多个操作或任务按照预定的顺序执行。

(1 利用wait/notify

package day01.tongbu;public class example1 {static final Object lock = new Object();//用于标记线程2是否已经执行完毕static boolean flag = false;public static void main(String[] args) {Thread t1 = new Thread(() -> {synchronized (lock) {while (!flag) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1 线程被唤醒,执行剩下的业务");}});Thread t2 = new Thread(() -> {synchronized (lock) {System.out.println("t2 线程执行完毕");flag = true;lock.notify();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

(2 使用ReentrantLock

package day01.tongbu;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class example3 {static boolean flag = false;static final ReentrantLock lock = new ReentrantLock();static final Condition condition = lock.newCondition();public static void main(String[] args) {// 实现先执行线程2,再执行线程1Thread t1 = new Thread(() -> {// 获取锁,未获取将阻塞lock.lock();try {while (!flag) {System.out.println("线程1等待线程2");condition.await();}Thread.sleep(500);System.out.println("线程1开始执行");Thread.sleep(500);System.out.println("线程1完成工作");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}});Thread t2 = new Thread(() -> {lock.lock();try {System.out.println("线程2开始执行");Thread.sleep(500);System.out.println("线程2执行完毕");flag = true;condition.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

(3 借助park/unpark

package day01.tongbu;import java.util.concurrent.locks.LockSupport;public class example4 {public static void main(String[] args) {Thread t1 = new Thread(() -> {System.out.println("t1等待....");LockSupport.park();System.out.println("t1运行");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1结束");});Thread t2 = new Thread(() -> {System.out.println("t2开始运行");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t2结束并标记t1");LockSupport.unpark(t1);});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

(对比

特性synchronized + wait/notifyReentrantLock + ConditionLockSupport
实现复杂度
性能中等最高
灵活性
多条件支持
公平锁选项
超时控制
唤醒先于阻塞
锁获取尝试
内存占用
适用场景简单同步复杂同步简单阻塞/唤醒

(4 实现多个线程交替执行

使用ReentractLock

package day01.tongbu;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class example5 {static ReentrantLock lock = new ReentrantLock();static Condition conditionA = lock.newCondition();static Condition conditionB = lock.newCondition();static Condition conditionC = lock.newCondition();static int flag = 1;static final int MAX_LOOP = 5; // 控制打印5次ABCpublic static void main(String[] args) {Thread t1 = new Thread(() -> {lock.lock();try {for (int i = 0; i < MAX_LOOP; i++) {while (flag != 1) {conditionA.await();}System.out.print("A");flag = 2;conditionB.signal();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}});Thread t2 = new Thread(() -> {lock.lock();try {for (int i = 0; i < MAX_LOOP; i++) {while (flag != 2) {conditionB.await();}System.out.print("B");flag = 3;conditionC.signal();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}});Thread t3 = new Thread(() -> {lock.lock();try {for (int i = 0; i < MAX_LOOP; i++) {while (flag != 3) {conditionC.await();}System.out.print("C");flag = 1;conditionA.signal();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}});t1.start();t2.start();t3.start();// 等待所有线程执行完毕try {t1.join();t2.join();t3.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

模块化

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class example5 {static ReentrantLock lock = new ReentrantLock();static Condition[] conditions = new Condition[3];static int currentFlag = 0; // 0 -> A, 1 -> B, 2 -> Cstatic final int MAX_LOOP = 5;public static void main(String[] args) {// 初始化每个 conditionfor (int i = 0; i < conditions.length; i++) {conditions[i] = lock.newCondition();}// 启动三个线程Thread t1 = new PrintThread(0, 'A', 1).getThread();Thread t2 = new PrintThread(1, 'B', 2).getThread();Thread t3 = new PrintThread(2, 'C', 0).getThread();t1.start();t2.start();t3.start();// 等待全部完成try {t1.join();t2.join();t3.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("全部打印完成!");}static class PrintThread {private final int id;private final char toPrint;private final int nextId;public PrintThread(int id, char toPrint, int nextId) {this.id = id;this.toPrint = toPrint;this.nextId = nextId;}public Thread getThread() {return new Thread(() -> {lock.lock();try {for (int i = 0; i < MAX_LOOP; i++) {while (currentFlag != id) {conditions[id].await();}System.out.println(toPrint);currentFlag = nextId;conditions[nextId].signal();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}});}}
}

3 Balking模式(犹豫模式)

当某个线程发现另一个线程已经执行了相同的操作时,放弃当前操作并直接返回,避免重复操作导致的资源浪费或状态不一致。

Balking 模式的核心是 避免重复操作和无效操作,通过状态检查确保操作只在合适的状态下执行。

实现多次访问不再重复创建

package day01;public class ax5 {public static void main(String[] args) throws InterruptedException {TwoPhaseTermination tpt = new TwoPhaseTermination();tpt.start();tpt.start(); // 被balking拒绝Thread.sleep(3500);tpt.stop();// 测试重启功能Thread.sleep(500);tpt.start(); // 应能重新启动Thread.sleep(1500);tpt.stop();}
}class TwoPhaseTermination {private Thread monitor;// stop 这个状态是判断是否已经停止,防止调用stop时出错,而state状态用来判断当前是否正在运行private volatile boolean stop = false;private static final int NEW = 0;private static final int RUNNING = 1;private volatile int state = NEW;public synchronized void start() {if (state != NEW) {System.out.println(Thread.currentThread().getName() + ": 拒绝重复启动");return;}state = RUNNING;stop = false;monitor = new Thread(() -> {try {while (!stop) {try {Thread.sleep(1000);System.out.println("执行监控记录");} catch (InterruptedException e) {System.out.println("睡眠中被中断,准备退出");}}} finally {synchronized (TwoPhaseTermination.this) {state = NEW; // 关键修改:重置为NEW而非TERMINATED}System.out.println("料理后事,释放资源");}}, "monitor");monitor.start();}public synchronized void stop() {if (state != RUNNING) return;stop = true;if (monitor != null) {monitor.interrupt();}}
}

二 线程管理/生命周期模式

1 两阶段终止模式

两阶段终止模式(Two-Phase Termination Pattern)是一种多线程编程中安全终止线程的设计模式。它的核心思想是:在终止线程前,先发出终止请求(第一阶段),然后线程在完成必要清理工作后再真正终止(第二阶段)。这种模式避免了直接强制终止线程导致的资源泄露、数据不一致等问题

简单来说就是在一个线程T1中如何优雅的终止线程T2,给T2一个料理后事的机会

在某些线程正在运行时如何正确终止线程,如果强制stop会带来相对应的问题:

  • 1 资源未释放:线程可能持有锁或者打开文件或者网络连接未关闭
  • 2 数据不一致:线程可能正在修改共享数据,突然终止会导致数据损坏。
  • 3 不可控性:无法保证线程在安全点终止。

(1 使用interrupt

需要借助interrupt进行打断,存在一个中断标志位,可以在这个中断循环之外将其他需要善后的地方再进行操作,可实现优雅终止。在下面代码实现的过程当中需要注意是在睡眠当中还是在运行当中被打断。

代码当中先开启工作线程,线程两个判断,如果isInterrupted==true就是执行了interrupt()将线程打断(模拟将后事料理),而另一种情况就是没有被打断就休眠1s(模拟工作过程),主线程先休眠再打断工作线程。

package day01;public class ax5 {public static void main(String[] args) {TwoPhaseTermination tpt = new TwoPhaseTermination();tpt.start();try {Thread.sleep(3500);} catch (InterruptedException e) {System.out.println("main thread stop");}tpt.stop();}
}class TwoPhaseTermination {private Thread monitor;public void start() {monitor = new Thread(() -> {while (true) {Thread current = Thread.currentThread();if (current.isInterrupted()) {System.out.println("打断线程,料理后事");break;} else {try {Thread.sleep(1000);System.out.println("执行监控记录");} catch (InterruptedException e) {current.interrupt();// 重置标志位位}}}});monitor.start();}public void stop() {monitor.interrupt();}
}

补充:

interrupted()静态方法当前线程(调用 Thread.interrupted()
isInterrupted()实例方法指定线程对象(如 thread.isInterrupted()
interrupted()- 当前线程需要检查中断状态并主动清除标志(如处理完中断后)。
- 需要确保中断状态不会被后续逻辑误判(如循环中检查中断状态)。
isInterrupted()- 检查其他线程的中断状态(如监控子线程是否被中断)。
- 需要多次检查中断状态且保留标志位(如在循环中持续监控)。

(2 使用volatile改进两阶段终止模式

设置一个volatile共享变量,实现线程之间共享

package day01;public class ax5 {public static void main(String[] args) {TwoPhaseTermination tpt = new TwoPhaseTermination();tpt.start();try {Thread.sleep(3500);} catch (InterruptedException e) {System.out.println("main thread stop");}tpt.stop();}
}class TwoPhaseTermination {private Thread monitor;// 保证共享变量在多线程之间的可见性private volatile boolean flag = false;public void start() {monitor = new Thread(() -> {while (true) {Thread current = Thread.currentThread();if (flag) {System.out.println("打断线程,料理后事");break;} else {try {Thread.sleep(1000);System.out.println("执行监控记录");} catch (InterruptedException e) {// 重置标志位位current.interrupt();}}}});monitor.start();}public void stop() {flag  = true;// 打断监控线程(中断在睡眠期间的线程,不加的话需要等待睡眠结束)monitor.interrupt();}
}

三 异步模式

1 生产者消费者模式

消费者与生产者之间的协调关系,为了解决生产过剩的情况或者说消费过多,这里的缓冲区相当于就是一个物品的储物箱,达到最大说明生产者生产太多了,达到最小说明消费者消费太多了。当达到最大就让生产者进入等待队列,唤醒消费者,反之就让消费者进入等待队列,唤醒生产者。

借助ReentrantLock与条件变量

package day01.lockax;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class Conditional {private final ReentrantLock lock = new ReentrantLock();private final Condition notEmpty = lock.newCondition();  // 消费者等待条件private final Condition notFull = lock.newCondition();   // 生产者等待条件private final int[] buffer = new int[5];                 // 缓冲区private int count = 0;                                   // 当前缓冲区元素数量// 生产者方法:向缓冲区添加元素public void produce(int item) throws InterruptedException {lock.lock();try {// 如果缓冲区已满,等待while (count == buffer.length) {System.out.println("缓冲区已满,生产者等待...");notFull.await();  // 释放锁并等待}// 添加元素到缓冲区buffer[count++] = item;System.out.println("生产者生产了: " + item + ",当前缓冲区大小: " + count);// 唤醒消费者notEmpty.signal();} finally {lock.unlock();}}// 消费者方法:从缓冲区取出元素public void consume() throws InterruptedException {lock.lock();try {// 如果缓冲区为空,等待while (count == 0) {System.out.println("缓冲区为空,消费者等待...");notEmpty.await();  // 释放锁并等待}// 从缓冲区取出元素int item = buffer[--count];System.out.println("消费者消费了: " + item + ",当前缓冲区大小: " + count);// 唤醒生产者notFull.signal();} finally {lock.unlock();}}// 测试生产者-消费者模型public static void main(String[] args) {Conditional example = new Conditional();// 启动生产者线程Thread producer = new Thread(() -> {for (int i = 1; i <= 10; i++) {try {example.produce(i);Thread.sleep(500);  // 模拟生产耗时} catch (InterruptedException e) {e.printStackTrace();}}});// 启动消费者线程Thread consumer = new Thread(() -> {for (int i = 1; i <= 10; i++) {try {example.consume();Thread.sleep(800);  // 模拟消费耗时} catch (InterruptedException e) {e.printStackTrace();}}});producer.start();consumer.start();}
}

2 工作线程(线程池)

核心:不同的任务类型使用不同的线程池。

代码展示:

package threadPool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;public class RestaurantThreadPoolExample {// 封装服务员任务逻辑private static void waiterTask(ExecutorService cookerPool, int taskId) {System.out.println("服务员[" + taskId + "] 处理点餐");Future<String> dishFuture = cookerPool.submit(() -> {// 模拟烹饪时间Thread.sleep(500);return "菜品[" + taskId + "] 完成 - 由厨师" + Thread.currentThread().getName();});try {// 模拟处理其他事务的时间Thread.sleep(300);System.out.println("服务员[" + taskId + "] 取菜: " + dishFuture.get());} catch (Exception e) {System.err.println("任务[" + taskId + "] 出错: " + e.getMessage());}}public static void main(String[] args) {// 创建有意义的线程池名称final int NUM_WAITERS = 5;final int NUM_COOKERS = 2;ExecutorService waitersPool = Executors.newFixedThreadPool(NUM_WAITERS);ExecutorService cookerPool = Executors.newFixedThreadPool(NUM_COOKERS);// 提交所有服务员任务for (int i = 1; i <= NUM_WAITERS; i++) {final int taskId = i;waitersPool.execute(() -> waiterTask(cookerPool, taskId));}// 优雅关闭线程池waitersPool.shutdown();try {// 等待服务员任务完成(包含它们提交的厨师任务)if (!waitersPool.awaitTermination(5, TimeUnit.SECONDS)) {System.err.println("警告: 服务员线程池未及时关闭");}} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {cookerPool.shutdown();try {// 确保厨师任务完成if (!cookerPool.awaitTermination(2, TimeUnit.SECONDS)) {System.err.println("警告: 厨师线程池未及时关闭,强制终止剩余任务");cookerPool.shutdownNow();}} catch (InterruptedException e) {cookerPool.shutdownNow();Thread.currentThread().interrupt();}}System.out.println("====== 所有任务执行完成 ======");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86615.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue 数据代理机制对属性名的要求

Vue 数据代理机制对属性名的要求 在 Vue 的数据代理机制中,属性名需遵循以下关键规则: 1. 禁止以 _ 或 $ 开头 ⚠️ Vue 会跳过代理以 _ 或 $ 开头的属性原因:这些前缀被 Vue 保留用于内部属性(如 _data, _uid, $refs, $el 等)示例:data() {return {count: 1, // ✅…

pdf.js在iOS移动端分页加载优化方案(ios移动端反复刷新加载问题)

背景与问题 在iOS移动端加载大型PDF文件时&#xff0c;由于设备内存限制&#xff0c;经常遇到以下问题&#xff1a; 内存不足导致页面崩溃大文件加载缓慢页面反复重新加载 ##解决方案 采用PDF.js的分页加载策略&#xff0c;实现按需加载当前可视页面及相邻页面&#xff0c;…

【C++】来学习使用set和map吧

各位大佬好&#xff0c;我是落羽&#xff01;一个坚持不断学习进步的大学生。 如果您觉得我的文章有所帮助&#xff0c;欢迎多多互三分享交流&#xff0c;一起学习进步&#xff01; 也欢迎关注我的blog主页: 落羽的落羽 文章目录 一、set和map是什么二、set系列1. set2. mult…

h5st逆向分析

h5st最新5.1版本逆向分析 申明定位h5st生成的位置动态插桩,事半功倍日志分析,十分钟还原算法逻辑申明 本文仅用来记录学习过程以免日后忘了,如有侵权请联系删除。 定位h5st生成的位置 通过关键字“sign”搜索,可以定位到window.PSign.sign(f)这个位置,f参数的值为{ &qu…

湖北理元理律师事务所企业债务优化路径:司法重整中的再生之道

一、企业债务危机的核心矛盾&#xff1a;生存与清偿的博弈 通过分析湖北理元理律师事务所经办的17件企业债务案件&#xff0c;发现共性难题&#xff1a; 债权人要求立即清偿 → 企业需持续经营造血 → 司法程序存在时间差 解决方案&#xff1a;构建“三重防火墙”机制 经…

链家Android面试题及参考答案

目录 请详细解释类加载的过程,包括每一步的具体实现。并说明Android中的dex分包技术及其在热更新中的应用 比较JVM和DVM的区别。在JVM中一个程序崩溃是否可能导致系统崩溃?DVM中呢? 请解释网络IP协议、TCP、UDP、HTTP、HTTPS、Socket的概念,并说明它们之间的区别 请深入…

LeetCode-多语言实现冒泡排序以及算法优化改进

目录 一、冒泡排序算法 二、应用场景/前提条件 &#x1f308; 优点 &#x1f4e2; 缺点 三、经典算法实现并优化改进 方法一&#xff1a;记录最后一次交换位置&#xff0c;下一轮只遍历到该位置 方法二&#xff1a;添加标志位跟踪是否发生交换&#xff0c;无交换则提前终…

JAVA毕业设计227—基于SpringBoot+hadoop+spark+Vue的大数据房屋维修系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于SpringBoothadoopsparkVue的大数据房屋维修系统(源代码数据库)227 一、系统介绍 本项目前后端分离&#xff0c;分为业主、维修人员、管理员三种角色 1、业主&#xff1a; 登…

MADlib —— 基于 SQL 的数据挖掘解决方案(9)—— 数据探索之概率统计

目录 一、概率 1. 概率的定义 2. 概率质量函数与概率密度函数 3. 条件概率 4. 期望值 二、MADlib 的概率相关函数 1. 函数语法 2. 示例 &#xff08;1&#xff09;求标准正态分布下&#xff0c;1 的概率密度函数 &#xff08;2&#xff09;求标准正态分布下&#xff…

耳蜗里的春天

早春的郑州飘着细雨&#xff0c;我牵着女儿小满的手走进市残疾人康复中心时&#xff0c;玻璃门内突然传来一阵清脆的笑声。穿天蓝色毛衣的小女孩戴着粉色耳蜗&#xff0c;正踮脚拍打着墙上的卡通贴画&#xff0c;银色的连接线在她耳后晃动&#xff0c;像一只折翼却仍在起舞的蝴…

OCR(光学字符识别)算法

OCR&#xff08;光学字符识别&#xff09;算法在景区护照阅读器中的应用是核心技术之一&#xff0c;它通过图像处理和机器学习快速提取护照信息&#xff0c;显著提升自动化水平。以下是其具体应用场景、技术实现及优化方向&#xff1a; 一、OCR在护照阅读器中的核心作用 关键信…

html打印合同模板

概述&#xff08;吐槽&#xff09;&#xff1a;记录一个html打印合同模板的功能&#xff0c;技术栈有点杂&#xff0c;千禧年出产老系统的数据库是sqlserver2008&#xff0c;原系统框架是c#&#xff0c;无法二开&#xff0c;因为原系统的合同生成功能出现bug&#xff0c;没有供…

DeepCritic: SFT+RL两阶段训练突破LLM自我监督!显著提升大模型的自我批判能力!!

摘要&#xff1a;随着大型语言模型&#xff08;LLMs&#xff09;的迅速发展&#xff0c;对其输出进行准确反馈和可扩展监督成为一个迫切且关键的问题。利用LLMs作为批评模型以实现自动化监督是一个有前景的解决方案。在本研究中&#xff0c;我们专注于研究并提升LLMs在数学批评…

【深度学习】深度学习中的张量:从多维数组到智能计算单元

✅ 一、n维数组&#xff08;张量&#xff0c;Tensor&#xff09; 1. 定义 张量&#xff08;Tensor&#xff09;是一个通用的n维数组数据结构。 它的维度&#xff08;维数&#xff09;决定了它的形状&#xff0c;例如&#xff1a; 维度名称举例说明0维标量&#xff08;scalar…

以太网MDI信号PCB EMC设计要点

1. PHY侧和RJ45连接器侧通用MDI布局建议 1. MDI差分对保持对称走线&#xff0c;走线上的焊盘封装应一致&#xff0c;焊盘放置位置也应对称。可以减少EMI测试中的模式转换。   2. MDI走线应保持阻抗匹配&#xff0c;从而减少信号线上的反射。   3. MDI走线下需有连续完整的接…

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…

pysnmp模块中 GET、SET、WALK操作详细分步解析

1. SNMP GET 操作详解 1.1 核心代码结构 from pysnmp.hlapi import *# 定义参数 community public # SNMPv2c 社区名 target_ip 192.168.1.1 # 目标设备 IP oid 1.3.6.1.2.1.1.1.0 # 要查询的 OID# 发起 GET 请求 error_indication, error_status, error_index, …

接收rabbitmq消息

以下是一个使用纯Java&#xff08;非Spring Boot&#xff09;接收RabbitMQ消息的完整实现&#xff0c;包含Maven依赖和持续监听消息的循环&#xff1a; 1. 首先添加Maven依赖 (pom.xml) <dependencies><!-- RabbitMQ Java Client --><dependency><group…

SQL进阶之旅 Day 23:事务隔离级别与性能优化

【SQL进阶之旅 Day 23】事务隔离级别与性能优化 文章简述 在数据库系统中&#xff0c;事务是确保数据一致性和完整性的核心机制。随着业务复杂度的提升&#xff0c;如何合理设置事务隔离级别以平衡并发性能与数据一致性成为开发人员必须掌握的关键技能。本文深入解析事务隔离级…

六.原型模式

一.原型模式的定义 原型模式是一种创建型设计模式&#xff0c;通过复制现有对象&#xff08;原型&#xff09;生成新对象&#xff0c;避免重复初始化成本。需了解以下关键概念&#xff1a; ‌浅拷贝‌&#xff1a;复制基本类型字段&#xff0c;引用类型字段共享内存地址&#…