Java并发编程原理与实战二十一:线程通信wait¬ify&join
wait和notify
wait和notify可以实现线程之间的通信,当一个线程执行不满足条件时可以调用wait方法将线程置为等待状态,当另一个线程执行到等待线程可以执行的条件时,调用notify可以唤醒等待的线程。需要强调的是,在调用wait和notify时需要先获取锁,否则会抛出IllegalMonitorException异常。notify方法随机从等待的线程中唤醒一个线程执行,notifyAll方法唤醒所有的等待线程,这些线程竞争时间片。下面是一个使用wait和notify的例子:当写线程将signal唤醒标志为1时,读线程才可以读。
public class Demo {
private volatile int signal;
public synchronized int getSignal() {
System.out.println(Thread.currentThread().getName() + " 进入同步方法了");
if (signal != 1) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return signal;
}
public synchronized void setSignal(int signal) {
System.out.println(Thread.currentThread().getName() + " 唤醒了");
this.signal = signal;
notifyAll();
}
public static void main(String[] args) {
Demo demo = new Demo();
TaskOne taskOne = new TaskOne(demo);
TaskTwo taskTwo = new TaskTwo(demo);
// 开启读线程
new Thread(taskOne).start();
new Thread(taskOne).start();
new Thread(taskOne).start();
new Thread(taskOne).start();
// 开启写线程
new Thread(taskTwo).start();
}
}
public class TaskOne implements Runnable {
private Demo demo;
public TaskOne(Demo demo) {
this.demo = demo;
}
@Override
public void run() {
demo.getSignal();
}
}
public class TaskTwo implements Runnable {
private Demo demo;
public TaskTwo(Demo demo) {
this.demo = demo;
}
@Override
public void run() {
demo.setSignal(1);
}
}
2.用wait和notify实现生产者和消费者
public class Table {
private int count;
private static final int MAX_COUNT = 10;
public synchronized void push() {
while (count >= MAX_COUNT) {
try {
System.out.println(Thread.currentThread().getName() + "桌子已放满,生产者停止生产");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println(Thread.currentThread().getName() + "桌子上当前产品数量: "+ count);
// 桌上一有产品就唤醒消费者
notifyAll();
}
public synchronized void take() {
while (count <= 0) {
try {
System.out.println(Thread.currentThread().getName() + "桌子已空,消费者停止消费");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
System.out.println(Thread.currentThread().getName() + "桌上剩余产品: " + count);
// 当桌子上的产品被消费完后唤醒生产者
notifyAll();
}
}
public class Productor implements Runnable {
private Table table;
public Productor(Table table) {
this.table = table;
}
@Override
public void run() {
while (true) {
table.push();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Consumer implements Runnable {
private Table table;
public Consumer(Table table) {
this.table = table;
}
@Override
public void run() {
while (true) {
table.take();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo {
public static void main(String[] args) {
Table table = new Table();
Productor productor = new Productor(table);
Consumer consumer = new Consumer(table);
new Thread(productor).start();
new Thread(productor).start();
new Thread(productor).start();
new Thread(productor).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
}
}
2.join
调用join方法的线程会加塞到其他线程之前执行,被加塞的线程在调用join方法的线程执行完后才接着执行。
public class JoinDemo {
public void a(Thread joinThread) {
System.out.println("线程a开始执行...");
joinThread.start();
try {
// 当前线程阻塞直到joinThread执行完毕
joinThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程a执行结束...");
}
public void b() {
System.out.println("加塞线程开始执行...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("加塞线程执行结束...");
}
public static void main(String[] args) {
final JoinDemo demo = new JoinDemo();
final Thread joinThread = new Thread() {
@Override
public void run() {
demo.b();
}
};
new Thread() {
@Override
public void run() {
demo.a(joinThread);
}
}.start();
}
}
参考资料:
《java并发编程实战》龙果学院
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
2012-08-11 线性表之--顺序表
2012-08-11 线性表之--链表操作