1.死锁:
1.有多把锁
2.有多个线程
3.有同步代码块嵌套
在我们多线程程序中,使用了多把锁,造成线程之间互相等待,程序不往下走了
【注意:应该尽量避免死锁】
4.死锁案列
public class Tests {
public static void main(String[] args) {
// 线程1: 锁A、锁B 执行线程
new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁A"){
System.out.println("线程1:拿到了锁A,准备拿锁B");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized ("锁B"){
System.out.println("线程1:拿到了锁A和B");
}
} // 释放锁A
}
},"线程1").start();
// 线程2:锁B、锁A 执行线程
new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁B"){
System.out.println("线程2:拿到了锁B,准备拿锁A");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized ("锁A"){
System.out.println("线程2:拿到了锁B和A,执行线程");
}
}
}
},"线程2").start();
}
}
2.什么是等待唤醒机制
是多个线程间的一种【协作】机制,类似于公司里面你和同时属于职位晋升的竞争对手,但大部分时候你和同事都是合作完成工作
就是在一个线程进行了规定操作后,会进入无线等待状态【wait】,调用notify()方法唤醒其他线程来执行,其他线程执行完成后,进入无线等待【wait】,唤醒等待线程执行,以此类推,如果需要,可以使用notifyAll()来唤醒所有的等待线程
所以,我们说【wait/notify】就是线程间的一种协作机制
【实现等待唤醒机制程序:
1.必须使用锁对象调用wait()方法,让当前线程进入无线等待状态
2.必须使用锁对象调用notify/notifyAll()方法唤醒等待线程
3.调用wait/notify/notifyAll()方法的锁对象必须一致
【分析等待唤醒机制程序:
1.线程的调用依然是抢占式调度
2.线程进入无线等待状态,就不会占用CPU和锁对象(可以理解为线程释放),也不会抢占CPU和锁对象
3.如果实在同步锁或者Lock中,调用sleep()方法进入即使等待,不会释放CPU和锁对象(线程依然占用着)
- public void wait(): 让当前线程进入到无限等待状态,此方法必须锁对象调用
- public void notify(): 唤醒当前锁对象等待状态的线程,此方法必须锁对象调用
public class Tests {
public static void main(String[] args) {
Object obj = new Object();
//无限等待线程
new Thread(new Runnable() {
@Override
public void run() {
// 加一把锁,锁对象obj
synchronized (obj){
System.out.println("无限等待线程:准备进入无限等待状态...");
// 进入无限等待状态
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 如果打印下面的话说明被唤醒了
System.out.println("无限等待线程被其他线程唤醒");
}
}
}).start();
// 唤醒线程
new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj){
System.out.println("唤醒线程准备唤醒无限等待线程...");
obj.notify();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行下面打印的话,说明 唤醒线程 唤醒完毕
System.out.println("唤醒线程:唤醒完毕");
} // 释放锁
}
}).start();
}
}
public class Tests2 {
public static void main(String[] args) {
Object obj = new Object();
//无限等待线程
new Thread(new Runnable() {
@Override
public void run() {
// 加一把锁,锁对象obj
while (true){
synchronized (obj){
System.out.println("无限等待线程:准备进入无限等待状态...");
// 进入无限等待状态
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 如果打印下面的话说明被唤醒了
System.out.println("无限等待线程被其他线程唤
醒===========================");
}
}
}
}).start();
// 唤醒线程
new Thread(new Runnable() {
@Override
public void run() {
while (true){
synchronized (obj){
System.out.println("唤醒线程准备唤醒无限等待线程...");
obj.notify();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行下面打印的话,说明 唤醒线程 唤醒完毕
System.out.println("唤醒线程:唤醒完毕");
} // 释放锁
}
}
}).start();
}
}
3.线程的六种状态:
4.吃包子案列
包子类:
public class BaoZi {
boolean flag= false; // 表示包子的状态false没有,true有
String xianer = null; //包子馅儿
}
包子铺类:
// 包子铺线程
public class BaoZiPu extends Thread {
BaoZi baoZi ;
public BaoZiPu(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
//生产包子
while (true){
//加锁
synchronized (baoZi){
// 锁里面 判断包子有没有
if (baoZi.flag == true){
// 如果有包子就进入无线等待状态
try {
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果没有包子,就成产包子
if (baoZi.flag == false){
System.out.println("包子铺开始成产包子");
baoZi.xianer = " 牛肉馅";
baoZi.flag = true; // 包子生产完毕,有包子了
System.out.println("包子铺线程:已经生产完包子,吃货线程快来吃包子");
baoZi.notify(); //唤醒吃货线程
}
} // 释放锁
} // while循环
}
}
吃包子的
public class ChiHuo extends Thread{
BaoZi baoZi;
public ChiHuo(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
// 吃包子
while (true){
// 加锁
synchronized (baoZi){
// 锁里面:判断有没有包子
// 如果没有包子,进入无限等待状态
if (baoZi.flag == false){
try {
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果有包子,就吃包子
if (baoZi.flag == true){
System.out.println("吃货线程:开始吃包子,包子馅儿"+baoZi.xianer);
baoZi.flag = false; //包子吃完了
System.out.println("吃货线程:包子吃完了,唤醒包子铺线程生产包子");
baoZi.notify(); // 唤醒包子铺
}
}// 释放锁
}
}
}
测试类:
public class Tests {
public static void main(String[] args) {
// 创建包子对象
BaoZi baoZi =new BaoZi();
// 创建并启动包子铺线程
new BaoZiPu(baoZi).start();
//创建并启动吃货线程
new ChiHuo(baoZi).start();
}
}