线程死锁的产生
线程同步可以帮助我们解决多个线程操作同一个资源而导致数据不安全的问题,但线程同步也有可能产生隐患,假如一个线程中出现多个锁对象时,可能出现锁使用不当,导致锁与锁之前相互等待对方释放资源,从而形成一种 “相互等待”的僵局,这就是线程死锁。 例如哲学家吃饭
模拟线程死锁
public class DeadThread implements Runnable {
Object obj1 = new Object();
Object obj2 = new Object();
@Override
public void run() {
// 模拟线程死锁
// 如果当前线程为线程A 先拿到obj1锁 ,等待obj2锁资源
// 如果当前线程为线程B 先拿到obj2锁 ,等待obj1锁的资源
if(Thread.currentThread().getName().equals("线程A")){
synchronized (obj1){
System.out.println(Thread.currentThread().getName()+"拿到了obj1的锁");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我在等待obj2锁。。。。。");
synchronized (obj2){
System.out.println("我已经拿到了obj2锁。。。。");
}
}
}else{
//线程B
synchronized (obj2){
System.out.println(Thread.currentThread().getName()+"拿到了obj2的锁");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我在等待obj1锁。。。。");
synchronized (obj1){
System.out.println("我已经拿到了obj1锁,我和开心");
}
}
}
}
}
public static void main(String[] args) {
DeadThread dead = new DeadThread();
Thread th1 = new Thread(dead,"线程A");
Thread th2 = new Thread(dead,"线程B");
th1.start();
th2.start();
}
之所以会发生死锁,因为对象锁直接没有良好的“沟通”,导致互相获取对方的锁 ,进入等待中 ,可以通过线程类的几个方法 解决线程之间通信问题
二、线程通信的几个方法
wait() : 让当前线程处于等待中,会释放对象锁 ,但是不会自动唤醒,需要其他线程唤醒
notify() : 唤醒等待中的一个线程
notifyAll: 唤醒所有等待中的线程
他们都属性Object的方法,需要相同的对象 ,使用时 通过Object的对象调用
注意: 以上方法的调用必须满足两个条件: a、他们必须在同步代码块中执行, b、调用该方法的对象是锁对象
案例1:模拟3个人,张飞、李逵和刘备,来买电影票,售票员只有一张5元的钱,电影票5元钱一张。
-
张飞拿20元一张的人民币排在李逵和刘备的前面,李逵和刘备各拿了一张5元的人民币买票。
package com.j2008.waitnotify; /** * ClassName: TicketThread * Description: * date: 2020/11/10 11:27 * * @author wuyafeng * @version 1.0 softeem.com */ public class TicketThread implements Runnable{ //公共资源: int fiveCount=1; int twentyCount =0; @Override public void run() { //开始买票 如果是张飞,他是20元面值,其他都是5元 if(Thread.currentThread().getName().equals("张飞")){ //20元面值买票 takeTicket(20); }else{ // 5元面值买票 takeTicket(5); } } /** * 买票过程 给方法加同步 ,锁对象默认是 方法 * @param money */ public synchronized void takeTicket(int money){ if(money ==20){ // 验证 当前公共资源 中是否有3张5元 while(fiveCount<3){ //等待 System.out.println(Thread.currentThread().getName()+"不能买到票,要继续等待"); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 程序执行这里,说明 fiveCount >=3 System.out.println(Thread.currentThread().getName()+"正在买票。。"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } fiveCount-=3; twentyCount++; System.out.println(Thread.currentThread().getName()+"已经买到了票。。"); }else{ System.out.println(Thread.currentThread().getName()+"正在买票。。"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } fiveCount++; System.out.println(Thread.currentThread().getName()+"已经买到了票。。"); // 唤醒等待的线程 this.notify(); } } }
public static void main(String[] args) { TicketThread ticketThread = new TicketThread(); Thread th1 = new Thread(ticketThread,"张飞"); Thread th2 = new Thread(ticketThread,"李逵"); Thread th3 = new Thread(ticketThread,"刘备"); //开启线程 th1.start(); th2.start(); th3.start(); }