多线程学习 等待队列状态 死锁问题及其解决办法 五
程序员文章站
2022-05-04 18:51:07
...
java代码
package com.baigu.demo1;
public class TestWaitNotify {
public static void main(String[] args) throws Exception{
Object o = new Object();
SubThread t = new SubThread(o);
t.start();
synchronized (o){ //wait方法需要放在同步代码块中 主线程拿到o的锁
System.out.println("main 1");
o.wait(); //主线程进入对o的等待队列 并且释放主线程拥有的所有锁标记
System.out.println("main 2");
}
}
}
class SubThread extends Thread{
Object o;
public SubThread(Object o) {
this.o = o;
}
public void run(){
synchronized (o){
System.out.println("Sub 1");
o.notifyAll(); //将主线程释放出来 但是不会释放该线程拥有的锁标记
System.out.println("Sub 2"); //run方法结束 主线程才能拿到o的锁标记
}
}
}
执行结果
一个线程可以同时拥有多个对象的锁标记,意味同步代码块是可以嵌套的
死锁问题
解决办法 调用wait notify notifyAll方法
个人理解
synchronized关键字 解决多线程并发访问同一对象破坏原子操作造成数据不一致问题。
线程拿到对象的锁标记
一个线程可以同时拥有多个对象的锁标记,意味同步代码块是可以嵌套的,当线程阻塞
在锁池时,线程不会释放它已经拥有的对象锁标记(除非run方法结束),会造成死锁
问题。
java中任何一个对象都有一个锁标记 锁池 等待队列
线程间通信: 等待-通知
任何对象都有一个等待队列,用来存放线程。
Object wait()
t1: o.wait() 必须放在对o加锁的同步代码块中。会有两种结果 1.t1会释放其拥有的所有锁标记
2.同时t1会阻塞在o的等待队列中 (t1对o调用wait()方法)
t2: o.notify()/notifyAll() 必须放在对o加锁的同步代码块中,从o的等待队列中释放一个/全部线程
(t2.对o调用notify()或者是notifyAll()方法)
线程对对象调用wait() 方法进入该对象的等待队列中,靠别的线程对该对象调用notify()或者是notifyAll()
方法进行从该对象的等待队列中进行释放该线程
ArrayList 线程不安全 :所有的方法都不是同步方法
Vector 线程安全 :所有的方法都是同步方法
HashMap: 线程不安全 :所有的方法都不是同步方法
HashTable: 线程安全 :所有的方法都是同步方法
线程不安全:访问临界资源造成数据不一致
修饰符组合:
synchronized 和 static联用:是给当前类对象加锁,staitc修饰方法没有this.(因此没有当前对象)
synchronized 和 abstract联用: 不可以 没有意义,抽象方法没有代码块,synchronized修饰的是代码块
synchronized 和 构造方法联用:不可以 同步方法对当前对象加锁,而构造方法中当前对象还没有构造结束,
无法使用里面互斥锁标记