之前学习的线程都是单线程执行的,没有设计到线程之间的通讯。线程之间的通讯主要靠以下方法实现。
生产者消费者模式(管程法)
生产者消费者(管程法)实现思路
- 创建一个生产者线程:负责生产数据
- 创建一个消费者线程:负责消费数据
- 创建一个数据缓冲区:负责存储生产者生产的数据,并将数据交给消费者消费
实现代码
import com.sun.org.apache.xerces.internal.parsers.CachingParserPool;
/**
* 多线程中的生产者与消费者模式
*/
public class ProducerAndConsumerPattern {
public static void main(String[] args) {
Container container = new Container();
new Producer(container).start();
new Consumer(container).start();
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
//创建生产者
class Producer extends Thread{
Container container;
public Producer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.producer(new Chicken(i));
System.out.println("生产了第" + i +"只鸡" );
}
}
}
//创建消费者
class Consumer extends Thread{
Container container;
public Consumer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了第" + container.consumer().id + "只鸡");
}
}
}
//创建缓冲区
class Container{
//定义容器的大小
Chicken[] chickens = new Chicken[10];
//定义容器计数器
int count = 0;
//生产者生产
public synchronized void producer(Chicken chicken){
//如果容器满了,就通知消费者消费
while(count==chickens.length){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//生产者生产
chickens[count] = chicken;
count++;
//通知消费者消费
this.notifyAll();
}
//消费者消费
public synchronized Chicken consumer(){
//如果容器为空,就通知生产者生产
while(count==0){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//消费者消费
count--;
Chicken chicken = chickens[count];
//消费以后通知生产者生产
this.notifyAll();
return chicken;
}
}
结果:
因为我发现很多次操作都是生产者现将10只鸡生产好,消费者在消费,我就想可能是因为当消费者线程在阻塞等待的时候(因为count等于0),生产者线程抢到cpu使用权以后在很快的一瞬间就将10只鸡生产好了。所以我为了证明我的猜想,我就在生产者生产鸡的过程中,我让生产好一只鸡以后让生产者睡眠10毫秒:
import com.sun.org.apache.xerces.internal.parsers.CachingParserPool;
/**
* 多线程中的生产者与消费者模式
*/
public class ProducerAndConsumerPattern {
public static void main(String[] args) {
Container container = new Container();
new Producer(container).start();
new Consumer(container).start();
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
//创建生产者
class Producer extends Thread{
Container container;
public Producer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.producer(new Chicken(i));
System.out.println("生产了第" + i +"只鸡" );
}
}
}
//创建消费者
class Consumer extends Thread{
Container container;
public Consumer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了第" + container.consumer().id + "只鸡");
}
}
}
//创建缓冲区
class Container{
//定义容器的大小
Chicken[] chickens = new Chicken[10];
//定义容器计数器
int count = 0;
//生产者生产
public synchronized void producer(Chicken chicken){
//如果容器满了,就通知消费者消费
while(count==chickens.length){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//生产者生产
chickens[count] = chicken;
count++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//通知消费者消费
this.notifyAll();
}
//消费者消费
public synchronized Chicken consumer(){
//如果容器为空,就通知生产者生产
while(count==0){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//消费者消费
count--;
Chicken chicken = chickens[count];
//消费以后通知生产者生产
this.notifyAll();
return chicken;
}
}
结果如下:
竟然出现了先消费的情况。我刚开始还纳闷,为啥我都还没有通知消费者消费(因为要睡眠10毫秒以后再通知),它怎么就先消费了。后来我想了想,因为生产者和消费者是两条线程,我之前的猜测也对——消费者线程先抢到cpu进行消费,但是它一看count等于0,于是就等待生产者生产,生产者抢到cpu以后就开始生产了,然后再通知消费者消费。但是也有可能一开始就是生产者先抢到cpu,他进行生产,生产完一只鸡以后count就变为了1,然后它在睡眠10毫秒。但是在这10毫秒之间,消费者获得了cpu,消费者一看容器里面有一只鸡(count不等于0),她于是就消费了。所以才会出现上面这种情况。
信号灯法
思想:通过一个标志位来决定由那个线程来处理业务
代码:
public class SigalLampPattern {
public static void main(String[] args) {
TV tv = new TV();
new Play(tv).start();
new Watch(tv).start();
}
}
//表演者线程
class Play extends Thread{
TV tv;
public Play(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2==0){
tv.play("进击的巨人");
}else{
tv.play("火影忍者");
}
}
}
}
//观看者线程
class Watch extends Thread{
TV tv;
public Watch(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//SigalLamp
class TV{
//节目
String item;
//设置标志
boolean flag = true;
//表演者
public synchronized void play(String item){
//观看者观看节目,表演者等待
if(!flag){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("表演者表演了"+ item);
this.item = item;
//通知观看者观看
this.flag = !flag;
this.notifyAll();
}
//观看者
public synchronized void watch(){
//观看者观看
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("观看者观看了"+ item);
//通知表演者表演
this.flag = !flag;
this.notifyAll();
}
}
结果: