线程之间的通信问题
java提供的线程通信方法
- 下面的方法均是Object类提供的方法。
- 下面的方法只能在同步方法和同步块中使用,否则抛出异常。
| 方法名 | 作用 |
|---|---|
| final void wait() | 表示线程一直等待,直到其它线程通知,与sleep不同,会释放锁 |
| final void wait(ling timeout) | 指定等待的毫秒数 |
| final void notifiy() | 唤醒一个处于等待桩体的线程 |
| final void notifyAll() | 唤醒同一个对象上所有调用wait方法的线程,优先级别高的线程优先调度 |
生产消费者模式
- 不是指java中的设计模式,而是处理并发协作/通信的一种模式。
- 该模式用于应用层到服务层之间的操作。
- 应用场景:生产者和消费者的问题
- 假设仓库中只能存放一件产品,生产者将生产出来的产品存放到仓库,消费者将仓库在的产品取走消费。
- 如果仓库中没有产品,则生产者将产品放入仓库。否则就停止生产并等待,直到仓库中的商品被消费者取走为止。
- 如果仓库中放有产品,则消费者可以将产品取走消费,否则就停止消费并等待,直到仓库中再次放入产品为止。

线程通信
-
上面的生产者和消费者模式就是一个线程同步问题,生产者和消费者共享一个资源,并且生产者和消费者之间相互依赖,互为条件。
-
对于生产者,没有生产产品之前,需要通知消费者等待,而生产了产品之后,有需要告知消费者消费。
-
对于消费者,在消费之后,要通知生产者消费已结束,需要继续生产新的产品以供消费。
-
在生产者和消费者问题中,仅有synchronized是不够的
4.1 synchronized可以阻止并发更新同一个共享资源,实现同步
4.2 synchronized不能用来实现不同线程之间的消息传递(通信)
-
实现线程(生产消费模式)通信的方法:管程法和信号灯法
管程法
- 生产者:负责生产数据模块(这里的模块是:方法,对象,线程,进程)
- 消费者:负责处理数据模块(这里的模块是:方法,对象,线程,进程)
- 缓冲区:消费者不能直接使用生产者的数据,它们之间有一个缓冲区;
- 生产者将生成好的数据放入缓冲区,消费者从缓冲区拿要处理的数据。
- 这样做的好处:生产者和消费者没有直接交流,达到了解耦的效果,也提高了效率

程序
package com.cn.Callable;
public class ProuductorAndConsumer {
public static void main(String[] args) {
SynContainer synContainer=new SynContainer();
new Producer(synContainer).start();
new Consumer(synContainer).start();
}
}
//角色一 生产者
class Producer extends Thread{
//生产者对仓库进行操作 存
SynContainer synContainer;
public Producer(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
//开始生产 生产10个产品
for (int i =1; i <= 20; i++) {
synContainer.push(new Product(i));
System.out.println("生产第"+i+"个产品");
}
}
}
//角色二 消费者
class Consumer extends Thread{
//消费者对仓库进行操作 取
SynContainer synContainer;
public Consumer(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
//开始消费 消费20个产品
for (int i = 1; i <= 10; i++) {
System.out.println("消费第"+synContainer.pop().id+"个产品");
synContainer.pop();
}
}
}
//角色三 缓存区(仓库)
class SynContainer{
//假设仓库只能放10给产品
Product[] product=new Product[9];
int count=0;//计数器
//仓库功能一:生产者投入产品(存)
public synchronized void push(Product pro){
//当仓库没有到达最大容量的时候就可以生产
//当仓库满了就不能生产
if(count==product.length){
try {
this.wait();//此时线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
product[count]=pro;
count++;
//生产了产品就可以通知消费者消费
this.notifyAll();
}
//仓库功能二:消费者消费产品(取)
public synchronized Product pop(){
// 没有产品就只能够等待
if(count==0){
try {
this.wait();//此时线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;//从最后一个位置开始拿产品
Product pro=product[count];
//当消费者进行消费了仓库就有空间了,就可以通知生产者生产
this.notifyAll();
return pro;
}
}
//角色四 数据(产品)
class Product{
int id;
public Product(int id) {
this.id = id;
}
}
结果
生产第1个产品
生产第2个产品
生产第3个产品
生产第4个产品
生产第5个产品
生产第6个产品
生产第7个产品
生产第8个产品
生产第9个产品
生产第10个产品
消费第9个产品
消费第8个产品
消费第7个产品
消费第5个产品
消费第3个产品
消费第1个产品
生产第11个产品
生产第12个产品
生产第13个产品
生产第14个产品
生产第15个产品
生产第16个产品
生产第17个产品
生产第18个产品
生产第19个产品
生产第20个产品
消费第14个产品
消费第19个产品
消费第17个产品
消费第15个产品
信号灯法
- 联想红绿灯(红灯:车走人停,绿灯:人行车停)
- 注意信号灯法需要添加一个标志位flag
public class Test {
public static void main(String[] args) {
Tv tv=new Tv();
new Player(tv).start();
new Watcher(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){
this.tv.play("奇葩说");
}else {
this.tv.play("广告");
}
}
}
}
//消费者 观众
class Watcher extends Thread{
Tv tv;
public Watcher(Tv tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//同一个资源 电视
class Tv{
String voice;
/*
信号灯
如果为真:演员表演,观众等待
如果为假:观众观看,演员等待
*/
boolean flag=true;
//表演
public synchronized void play(String voice){
//演员等待
if(!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("表演了"+voice);
this.voice=voice;
//表演完毕,唤醒
this.notifyAll();
//切换标志
this.flag=!this.flag;
}
//观看
public synchronized void watch(){
//观众等待
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("听到了"+voice);
//唤醒
this.notifyAll();
//切换标志
this.flag=!this.flag;
}
}
结果
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
表演了奇葩说
听到了奇葩说
表演了广告
听到了广告
参考教程:尚学堂Java300集

浙公网安备 33010602011771号