<font size = 5>对比上面的两段代码,我们可以看到,当我们
i
的的值 循环次数较少时,发生线程安全的问题明显就减小了,但它任然存在线程安全问题。 <font size = 5>上面代码中当i很小时,t1就开始计算了,可能会出现:t2还没启动,t1就运行完了,此时这两个线程就相当于是串行执行。 <font size = 5><font color = red>通过对比上面两段多线程代码的运行结果:我们可以得出多线程代码运行具有随机性。
package thread;
class Counter2{
private int count = 0 ;
void add(){
count++;
}
int get(){
return count;
}
}
public class Demo21 {
public static void main(String[] args) throws InterruptedException {
Counter2 counter2 = new Counter2();
Thread t1 = new Thread(() -> {
for(int i = 0 ; i < 5000 ; i++){
synchronized (counter2){
counter2.add();
}
}
});
Thread t2 = new Thread(() -> {
for(int i = 0 ; i < 5000 ; i++){
synchronized (counter2){
counter2.add();
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("count = " + counter2.get());
}
}
<font size = 5><font color = red>如果一个线程加了锁另一个线程不加锁,那线程还安全吗?
<font size = 5><font color = red>多线程中如果有的线程未加锁,会发生线程不安全的情况,上面代码中
t2
未加锁,即使t1
加锁了,由于t2
没有任何阻塞,没有互斥,任然会使t1++
到一半的时候,被t2
进来把结果覆盖掉。 <font size = 5><font color = g>故事时间:上面的就好比两个男的追一个女的,但是这个女的和其它男的谈了,但是这两个男的依旧是穷追不舍,其中一个呢就比较老实一点,默默观望;另一个就是霸王硬上弓,恨不得打一架
<font size = 5><font color = g>假设t2先启动(t1先不考虑),t2线程第一次加锁肯定能成功,但当t2尝试第二次加锁时,此时counter2变量,属于已被锁定的状态,根据之前的知识,当我们针对一个已被锁定的线程加锁就会出现阻塞等待,并且会一直阻塞到对象被解锁时。 <font size = 5><font color = red>想要获取第二把锁,就需要先给第一把锁解锁,但是想要给第一把锁解锁就需要执行完第一层大括号,但执行完第一层大括号又需要先获取第二层锁,这两层加锁解锁操作相互矛盾,这种情况就叫做“死锁”。 <font size = 5><font color = blue>但是根据上面的运行结果,我们可以看到,这个结果是正确的,也就是说上述死锁过程对于<font color = red>“synchronized”<font color = blue>并不适用,<font color = green>但是对于C++/python 就会出现死锁的现象。
| 但是如果有N层锁,如何判定这个 } 是最外层的 } ,JVM如何识别? |
|:----|
<font color=blue><font size = 5> 故事时间:疫情期间,有一个地方的健康码崩了,程序员赶紧回公司去修复Bug,但他在楼下被保安拦住要求出示健康码才能上楼,但是程序员如果没有上楼修复好Bug就无法出示健康码,如果两个人你不让我我不让你,就会一直僵持,这就是死锁。
package thread;
public class Demo22 {
public static void main(String[] args) throws InterruptedException {
Object locker1 = new Object();
Object locker2 = new Object();
Thread t1 = new Thread(() -> {
synchronized(locker1){
//为了更好的控制线程的执行顺序,引入sleep,否则死锁可能会重现不出来
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized(locker2){
System.out.println("t1 获取两把锁");
}
}
});
Thread t2 = new Thread(() -> {
synchronized(locker2){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized(locker1){
System.out.println("t2 线程拿到两把锁");
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
___
____
嵌套锁
【代码结构】你等我我等你,谁都不主动的死等
【代码结构】<font color=red><font size = 5>⚠️注意:如果是自己实现的锁,就可以实现打破互斥,打破不可剥夺这两个条件,但是对于synchroniz
ed这样的锁就不行。
<font color=re><font size = 5>⭐️⭐️⭐️⭐️⭐️当代码中,需要用到多个线程获取多把锁,一定要约定好加锁顺序,可以有效避免死锁。如下所示:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。