老生常谈…对于大佬们根本都不用看的博客!
对于像我这种菜鸡还是得一步一步的来!如果有错误请大佬们指点指点!
线程通信
为什么要线程通信呢?
多线程在处理同一个资源的时候,处理的方法不同。
当多个线程并发执行时,CPU时随机切换线程的,当我们需要多个线程来同时完成一件事的时,我们希望这些线程能够有规律的执行,所有产生了一些通信机制来协调它们来完成工作。
线程之间的线程通信的机制被称为:等待唤醒机制。
等待唤醒机制
等待唤醒机制就是一个线程在完成一件操作后进入等待状态,然后等待其他线程执行后再将其唤醒,也可以通过指定时间,自动唤醒。
一般用三种方法实现:
- wait():让线程进入等待状态;
- notify():唤醒正在等待中里优先级最高的线程;
- notifyAll():唤醒所有等待中的线程;
注意:
- 线程被唤醒后不一定立即执行,因为它只有成功获取了锁后才能正常运行。成功获得锁后,可以等待执行,反之则继续等待。
- wait和notify必须由同一个对象调用;
- wait和notify属于Object类,是对象的方法;
- wait和notify必须要在同步代码块或同步方法中使用;
通过描述可知,线程通信就相当于一个线程负责生产,一个线程负责消费,生产成功后通知消费者消费。
生产者与消费者
因此线程安全和线程通信是这个代码问题的两个难点
废话不多说直接上代码:
物品
//物品
public class Goods {
//物品数量
int count;
//是否生产完成
boolean flag;
public synchronized void produce() {
if (this.flag) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.count++;
System.out.println("生产第" + this.count + "个");
this.flag = true;
this.notify();
}
public synchronized void consume() {
// flag为false,消费完成,等待生产
if (!this.flag) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费第" + this.count + "个");
this.flag = false;
this.notify();
}
}
生产者
//生产者
public class Product implements Runnable {
private final Goods goods;
public Product(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
this.goods.produce();
}
}
}
消费者
//消费者
public class Consume implements Runnable{
private final Goods goods;
public Consume(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
this.goods.consume();
}
}
}
测试
//测试类
public class Test {
public static void main(String[] args) {
Goods goods = new Goods();
Consume consume = new Consume(goods);
Product product = new Product(goods);
Thread consumeThread = new Thread(consume);
Thread productThread = new Thread(product);
consumeThread.start();
productThread.start();
}
}
可能出现的性能问题
- 频繁等待与唤醒,导致JVM 和 操作系统交互的次数过多;
- notifyAll() 唤醒全部的线程,也浪费线程资源,不要因为一个线程而唤醒所有线程;
sleep()和wait()的区别
- sleep() 不释放锁,wait() 释放锁;
- leep() 指定休眠的时间,wait() 可以指定时间也可以无限等待直到调用 notify() 或 notifyAll()
- sleep( )在 Thread 类中声明的静态方法,wait 方法在 Object 类中方法;