1、多线程死锁问题
因为由于锁的嵌套,就有可能导致死锁现象。
为了防止出现死锁问题,尽量不写嵌套锁,就能避免。
1.1、产生死锁的条件
1.有多把锁
2.有多个线程
3.有同步代码块嵌套
死锁测试:
public class MyThread extends Thread {
//创建两把锁对象
static Object objA = new Object();
static Object objB = new Object();
@Override
public void run() {
while (true) {
if("小黑".equals(getName())){
//当前线程是第一条小黑线程
synchronized (objA){
//小黑
synchronized (objB){
System.out.println("小黑在执行了");
}
}
}else{
//当前线程是第二条小美线程
synchronized (objB){
//小美
synchronized (objA){
System.out.println("小美在执行了~~~~~~~~~");
}
}
}
}
}
}
public class Test {
public static void main(String[] args) {
//创建两个线程对象
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
//给两条线程起名字
t1.setName("小黑");
t2.setName("小美");
t1.start();
t2.start();
}
}
2、多线程间的通信
多线程中有个状态叫计时等待,可以通过Thread类的方法来进行演示。
// 让当前线程进入到睡眠状态,到毫秒后自动醒来继续执行
public class Test{
public static void main(String[] args){
for(int i = 1;i<=5;i++){
Thread.sleep(1000);
System.out.println(i)
}
}
}
2.1 等待和唤醒(唤醒机制)
Object类的方法
public void wait()
: 让当前线程进入到等待状态 此方法必须锁对象调用.
public void notify()
: 唤醒当前锁对象上等待状态的线程 此方法必须锁对象调用.
2.2 等待唤醒案例(乘客三窗口上车)
Car类:
package cn.itxiaoli.homework.Demo02;
import java.util.Random;
/**
* @author xiaoli
* @className Car
* @description:
* @date 2022/3/18 19:22
*/
public class Car {
// 座位
public static int seat = 80;
// 状态 0 前面 1 中 2 后
public static int flag = 0;
// 随机对象
public static Random random = new Random();
// 锁对象
public static final Object OBJ = new Object();
}
door1类:
package cn.itxiaoli.homework.Demo02;
/**
* @author xiaoli
* @className door1
* @description:
* @date 2022/3/18 19:26
*/
public class door1 extends Thread {
//套路:
//1.while(true)
//2.同步代码块
//3.判断共享数据是否到末位-- 到了末尾
//4.判断共享数据是否到末位-- 没有到末尾
@Override
public void run() {
while (true) {
synchronized (Car.OBJ) {
// 座位为0时 跳出死循环
if (Car.seat == 0) {
break;
}
// 0 前门上车
if (Car.flag == 0) {
// 修改三个门的状态,利用随机数达到模拟现实生活中随机上车(0,1,2)
Car.flag = Car.random.nextInt(3);
// 此时已经上车一人做减减操作
Car.seat--;
System.out.println(getName() + "门上车---还剩" + Car.seat + "个座位");
// 唤醒等待的其他车门线程
//细节1:必须用wait方法,跟锁进行绑定,此时锁才知道要唤醒哪些线程
//细节2:如果没有线程在等待,那么也可以唤醒,没有任何问题。
Car.OBJ.notifyAll();
} else {
try {
// 当其他车门线程执行到这行代码的时候,就会等待并且跟前面锁对象绑定在一起
Car.OBJ.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
door2类:
package cn.itxiaoli.homework.Demo02;
/**
* @author xiaoli
* @className door2
* @description:
* @date 2022/3/18 19:26
*/
public class door2 extends Thread {
@Override
public void run() {
while (true) {
synchronized (Car.OBJ) {
if (Car.seat == 0) {
break;
}
// 中门上车
if (Car.flag == 1) {
// 随机上车
Car.flag = Car.random.nextInt(3);
Car.seat--;
System.out.println(getName() + "门上车---还剩" + Car.seat + "个座位");
Car.OBJ.notifyAll();
} else {
try {
Car.OBJ.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
door3类:
package cn.itxiaoli.homework.Demo02;
/**
* @author xiaoli
* @className door3
* @description:
* @date 2022/3/18 19:27
*/
public class door3 extends Thread {
@Override
public void run() {
while (true) {
synchronized (Car.OBJ) {
if (Car.seat == 0) {
break;
}
// 后门上车
if (Car.flag == 2) {
Car.flag = Car.random.nextInt(3);
Car.seat--;
System.out.println(getName() + "门上车---还剩" + Car.seat + "个座位");
System.out.println("-----------------------");
Car.OBJ.notifyAll();
} else {
try {
Car.OBJ.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
测试类:
package cn.itxiaoli.homework.Demo02;
/**
* @author xiaoli
* @className Test
* @description:
* @date 2022/3/18 19:27
*/
public class Test {
public static void main(String[] args) {
// 三个门的线程对象
door1 door1 = new door1();
door2 door2 = new door2();
door3 door3 = new door3();
// 设置车门线程名字
door1.setName("前");
door2.setName("中");
door3.setName("后");
// 开启线程
door1.start();
door2.start();
door3.start();
}
}
注意:
只要用wait和notify或者notifyAll就是等待唤醒机制。(根据输出结果的要求,破坏了多线程的随机性,相当于制订了执行了一种规则)。