给我一首歌的时间,带你了解线程安全和死锁(3)
大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流
作者简介:
- CSDN java领域新星创作者blog.csdn.net/bug…
- 掘金LV3用户 juejin.cn/user/bug…
- 阿里云社区专家博主,星级博主,developer.aliyun.com/bug…
- 华为云云享专家 bbs.huaweicloud.com/bug…
造成死锁的必要条件
- 互斥使用: 当一个锁被线程占用时,其他线程就不能占用该锁了(锁的本质,原子性)
- 不可抢占: 当一个锁被线程占用后,其他线程不能把该锁抢走(也就好比人家已经有对象,你就不能挖别人墙角)
- 请求和保持: 当一个线程占用多把锁后,如果不释放锁,那么这些锁始终被该线程所有!
- 环路等待: 就入哲学家就餐,同时拿筷子,造成了环路等待,a等b,b等c,c又等a!
避免环路等待,需要约定加锁顺序,然后线程都按照该顺序加锁!
synchronized
和volatile
区别
我们再来总结一下volatile
的作用!
volatile
关键字,可以保证该变量内存可见性,避免编译器偷懒优化,直接在寄存器中读取数据,导致线程不安全!
synchronized
:
-
给对象加锁,当多个线程对同一个变量更改时,保证线程安全
-
给变量加锁,保证指令原子性
-
保证内存可见性
-
避免指令重排序
可以看到synchronized
关键字,可以解决所有的线程不安全问题!
那我们是不是无脑用synchronized
就好了
但是我我们知道synchronized
加锁后,代码的执行效率就大打折扣!发挥不了多线程并发编程的优势!使用时需要视情况而定!!!
而volatile
只是保证了该变量内存可见性!并不能避免其他线程安全问题!
synchronized
加锁后,会造成线程阻塞,volatile
并不会导致阻塞!!!
wait 和notify方法
等待和通知线程
这两个方法是Object
类中的方法!
我们知道线程的调度是随机的,抢占性!而java
下的wait
和notify
方法可以保证线程的执行顺序!
我们来学习一下这两个方法的使用!
调用wait
方法后线程就会阻塞,直到有线程调用了notify
通知!
public class Thread_20 {
public static void main(String[] args) {
Thread t1 = new Thread(()->{
Object object = new Object();
System.out.println("wait前:");
try {
object.wait();//阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait后:");
});
t1.start();
t1.getState();
}
}
本来预期是线程阻塞结果却抛出非法的监听器状态异常!
我们来看看wait
方法的作用
- 释放锁
- 阻塞状态,等待其他线程通知
- 收到通知,重新获取锁,继续往下执行
而我们上述代码连锁都没有又如何释放锁呢!
所以wait
和notify
方法需要搭配synchronized
关键字使用!
正确用法:
public class Thread_21 {
private static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
//进行wait操作
System.out.println("wait前");
synchronized (object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("wait后");
});
t1.start();
t1.sleep(3000);
Thread t2 = new Thread(()->{
System.out.println("notify前");
synchronized(object){
object.notify();
}
System.out.println("notify后");
});
t2.start();
}
}
我们可以看到,当object
执行了wait
方法后就造成了线程阻塞,直到执行notify
通知后,线程才拿到锁继续执行下去!
notify
和notifyAll
区别
当我们多个线程都对object
加锁后,notify
通知后,只会随机给一个线程进行通知,然后该线程就可以拿到锁,执行线程!
而notifyAll
方法是通知所有阻塞线程,此时就会产生锁竞争!
- 点赞
- 收藏
- 关注作者
评论(0)