1、死锁
1.1 概述
1.2 代码实现
2、 线程通信
2.1
2.2 使用方式
2.3 生产者消费者
package day_02;
import java.util.Random;
/**
* 类似于打印奇数和偶数一样 , 使用 wait和notifyAll
*
* 1 一个业务类 SynStack 其中有一个变量,用来保存已生产的元素个数
* 2 业务类中有一个char数组,用于保存生产的元素(假如只生产 a-z这些字母)
* 3 业务类中需要有两个方法,一个是生产 push , 一个消费 pop
* push方法 主要用于向数组中添加数据
* 个数要+1 , 还要判断是否添加满了,满了就挂起进入等待
* pop 方法 主要用于取出数组中数据
* 个数要-1 , 还要判断是否消费完了,完了就挂起进入等待
* 4 两个线程,一个负责生产,一个负责消费
*
* @author 天亮教育-帅气多汁你泽哥
* @Date 2022年1月25日 上午11:14:56
*/
public class Thread_03_ProduceConsumer {
public static void main(String[] args) {
SynStack ss = new SynStack();
Thread p = new Thread(new Producer(ss));
Thread c = new Thread(new Consumer(ss));
p.start();
c.start();
}
}
class Producer implements Runnable{
SynStack ss ;
public Producer(SynStack ss) {
super();
this.ss = ss;
}
@Override
public void run() {
Random random = new Random();
while (true) {
char ch = (char) (random.nextInt(26)+97);
ss.push(ch);
}
}
}
class Consumer implements Runnable{
SynStack ss ;
public Consumer(SynStack ss) {
super();
this.ss = ss;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
ss.pop();
}
}
}
class SynStack{
// 保存数据的容器
char[] data = new char[6];
// 生产个数
int count = 0;
// 生产
public synchronized void push(char ch) {
// 判断是否满了
if (count == data.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 到这里说明没有满,开始生产
// 唤醒消费者准备消费
this.notifyAll();
data[count ] = ch;
count++;
System.out.println("生产了 "+ch+" , 剩余 "+count+" 个元素");
}
public synchronized char pop(){
// 判断是否为空
if (count == 0) {
try {
// 这里不用唤醒生产者,因为生产者是满了在wait,都为空了,说明生产者肯定没有wait
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 到这里说明不是空,开始消费
count--;
char ch = data[count];
// 唤醒生产者
this.notifyAll();
System.out.println("消费了 "+ch+" , 剩余 "+count+" 个元素");
return ch;
}
}
3. 单例模式