1.老规矩的吐槽,网上查这块内容的时候,全是理论方面的说明和复制粘贴,没找到一个完全用代码说明的例子。
2.饥饿死锁
直接上代码:
/**
* Created by
* Date : 2018/7/19 18:12
*/
public class Main {
public static void main(String[] args){
final ExecutorService executorService= Executors.newSingleThreadExecutor();
Future<String> strResult=executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Future<String> f=executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return null;
}
});
return f.get();
}
});
try{
System.out.println(strResult.get());
}catch (Exception e){
e.printStackTrace();
}
executorService.shutdown();
}
}
执行结果:
系统卡住了,运行不了了,只有重启才行
上面是如何造成饥饿死锁的?
一个单线程线程池,关于单线程线程池可以看我关于线程池方面的解说。单线程线程池在执行任务的时候,我们任务中却又执行了单线程线程池的另一个任务,但是单线程线程池一次只能执行一个任务,所以两个任务在互相等待另一个任务的完成,造成最终两个任务都无法完成,就造成了饥饿死锁的现象。其实所谓的饥饿死锁也就是死锁。不明白《java并发编程实战》这书为什么要称呼这种情况叫“饥饿死锁”。
2.死锁
老规矩,直接上代码:
/**
* Created by WangZhiXin
* Date : 2018/7/19 18:12
*/
public class Main {
private final Object obj1=new Object();
private final Object obj2=new Object();
public static void main(String[] args){
new Main().test2();
}
public void test2(){
new Thread("A"){
public void run(){
synchronized (obj1){
try{
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (obj2){
System.out.println("线程"+Thread.currentThread().getName()+"执行");
}
}
}
}.start();
new Thread("B"){
public void run(){
synchronized (obj2){
try{
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (obj1){
System.out.println("线程"+Thread.currentThread().getName()+"执行");
}
}
}
}.start();
}
}
执行结果:
系统卡住了,运行不了了,只有重启才行
上面是如何造成死锁的?
线程A持有obj1锁,线程B持有obj2锁,线程A往下执行程序需要获取obj2锁,但是obj2锁这时被线程B持有,线程B要想释放obj2锁,必须执行完程序,往下执行,但线程B执行程序又需要获取obj1的锁,但obj1的锁却被线程A所持有。所以,造成了线程A等待线程B释放obj2锁,线程B却又在等待线程A释放obj1锁,所以两不相让,就造成了死锁。
3.活锁
直接上代码:
/**
* Created by
* Date : 2018/7/19 18:12
*/
public class Main {
public static void main(String[] args){
Person a = new Person("A");
Person b = new Person("B");
a.friend = b;
b.friend = a;
a.bow();
new Thread(a).start();
new Thread(b).start();
}
}
/**
* Created by
* Date : 2018/7/20 10:52
*/
public class Person implements Runnable{
Person friend;
String name;
public Person(String name){
this.name=name;
}
boolean flag = false;
public void bow() {
System.out.println(name+".flag=true");
flag = true;
}
public void up() {
System.out.println(name+".flag=false");
flag = false;
}
public void run() {
while (friend.flag) {
System.out.println(name+"执行");
this.bow();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.up();
}
}
}
执行结果:
A.flag=true
B执行
B.flag=true
A执行
A.flag=true
B.flag=false
B执行
B.flag=true
A.flag=false
A执行
A.flag=true
B.flag=false
B执行
B.flag=true
A.flag=false
A执行
A.flag=true
B.flag=false
B执行
。。。。。。
这个结果会无限循环下去。但是这儿要说明一下,有时候运行结果得的是这个,有时候运行结果不是这个,活锁出现的概率也是随机的。那么我们分析一下这个程序为什么会无限循环下去。
首先A因为friend(属性值是B)的flag=false,所以直接执行B,然后B.flag=true;这时候B休眠了,但是A因为B的flag=true可以执行A的循环了,然后A.flag=true;A又休眠了,这时候B从休眠中醒过来,因为前面A执行了flag=true,所以B又可以循环执行了,然后B.flag又等于true了,然后又休眠了,A因为B的flag=true,所以A这时候醒过来,A又可以循环执行了。以此往复,就造成了程序永远在运行,永远结束不了。
所以,这就是活锁,线程没有阻塞,但是会不断重复执行相同的操作。