java线程九之饥饿死锁,死锁与活锁

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();
    }
}

执行结果:

系统卡住了,运行不了了,只有重启才行

扫描二维码关注公众号,回复: 2276849 查看本文章

上面是如何造成死锁的?

线程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又可以循环执行了。以此往复,就造成了程序永远在运行,永远结束不了。

所以,这就是活锁,线程没有阻塞,但是会不断重复执行相同的操作。

猜你喜欢

转载自blog.csdn.net/wangzx19851228/article/details/81120629