线程协作、线程通信
3个解决线程中间通信问题的方法
方法 | 描述 |
---|---|
final void wait() | 线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
final void wait(long timeout) | 指定等待的毫秒数 |
final void notify() | 唤醒一个处于等待状态的线程 |
final void notifyAll() | 唤醒同一个对象上所有调用wait方法的线程,优先级高的线程优先调度 |
1、生产者消费者模式
解决线程通信问题
管程法
使用容器作为缓冲区(buffer 共享内存)实现
- 生产者:负责生产数据的模块(可能是方法、对象、线程、进程)
- 消费者:负责处理数据的模块(可能是方法、对象、线程、进程)
- 缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区,生产者将生产的数据放入缓冲区,消费者从缓冲区拿需要的数据
package com.tsymq.thread.concurrentcollaboration;
public class ProducerConsumer {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Producer(container).start();
new Consumer(container).start();
}
}
// 生产者
class Producer extends Thread{
SynContainer container;
public Producer(SynContainer container) {
this.container = container;
}
@Override
public void run() {
// 生产
for (int i = 1; i <= 200; i++) {
System.out.println("生产第" + i + "个数据");
container.push(new Data(i));
}
}
}
// 消费者
class Consumer extends Thread{
SynContainer container;
public Consumer(SynContainer container) {
this.container = container;
}
@Override
public void run() {
// 消费
for (int i = 1; i <= 200; i++) {
System.out.println("消费第" + container.pop().id + "个数据");
}
}
}
// 缓冲区
class SynContainer{
Data[] dataBuffer = new Data[10];
int count = 0;
// 存储 生产
public synchronized void push(Data data){
// 当容器还剩余空间时才能生产
if (count == dataBuffer.length){ // 容器已满,无法生产
try {
this.wait(); // 线程阻塞,等待消费者通知生产时解除阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 存在空间,可以生产
dataBuffer[count] = data;
// 容器里有数据了,通知消费者可以获取数据
this.notify();
count++;
}
// 获取 消费
public synchronized Data pop(){
// 当容器中存在数据时,才能消费
// 若无数据只能等待
if (count == 0){
try {
this.wait(); // 线程阻塞,生产者放入数据时,通知解除阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 存在数据,可以消费
count--;
// 容器里有空间了,通知生产者可以生产数据
this.notify(); // this.notifyAll();
return dataBuffer[count];
}
}
// 数据
class Data{
int id;
public Data(int id) {
this.id = id;
}
}
信号灯法
借助标志位
package com.tsymq.thread.concurrentcollaboration;
public class SignalLight {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Audience(tv).start();
}
}
// 生产者 演员
class Player extends Thread{
TV tv;
public Player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++){
if (i%2 == 0){
tv.play("卢本伟NB!");
} else {
tv.play("假猪套天下第一!");
}
}
}
}
// 消费者 观众
class Audience extends Thread{
TV tv;
public Audience(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++){
tv.watch();
}
}
}
// 同一个资源 电视
class TV{
String voice;
// 信号灯
// T 表示演员表演,观众等待
// F 表示观众观看,演员等待
boolean light = true;
// 表演
public synchronized void play(String voice){
// 演员等待
if(!light){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 开始表演
System.out.println("表演:" + voice);
this.voice = voice;
// 表演了一段,让观众看
this.notify();
// 切换信号灯
this.light = !this.light;
}
// 观看
public synchronized void watch(){
// 观众等待
if(light){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 开始观看
System.out.println("听到:" + voice);
// 看完了,通知演员继续表演
this.notify();
// 切换信号灯
this.light = !this.light;
}
}