侧边栏壁纸
博主头像
Sir丶雨轩博主等级

一个90的萌新码农,热爱编程热爱生活 编程交流群:875477818

  • 累计撰写 48 篇文章
  • 累计创建 81 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Java 死锁(Deadlock)、饥饿(Starvation)和活锁(Livelock)

Sir丶雨轩
2020-06-29 / 0 评论 / 1 点赞 / 110 阅读 / 4,015 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-12-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

死锁

产生死锁原因:线程0 想要得到obj2 锁进行下面的操作,而obj2锁被线程1 所占有。
线程1想得到obj1锁 进行下面的操作,而obj1锁被线程0 所占有。

public class DeadlockDemo {
    public static void main(String[] args) {
        DieLock d1 = new DieLock(true);
        DieLock d2 = new DieLock(false);
        Thread t1 = new Thread(d1);
        Thread t2 = new Thread(d2);
        t1.start();
        t2.start();
    }
}
class MyLock {
    public static final Object obj1 = new Object();
    public static final Object obj2 = new Object();
}
class DieLock implements Runnable {
    private final boolean flag;
    DieLock(boolean flag) {
        this.flag = flag;
    }
    public void run() {
        if (flag) {
            while (true) {
                synchronized (MyLock.obj1) {
                    System.out.println(Thread.currentThread().getName() + "....if...obj1...");
                    synchronized (MyLock.obj2) {
                        System.out.println(Thread.currentThread().getName() + ".....if.....obj2.....");
                    }
                }
            }
        } else {
            while (true) {
                synchronized (MyLock.obj2) {
                    System.out.println(Thread.currentThread().getName() + "....else...obj2...");
                    synchronized (MyLock.obj1) {
                        System.out.println(Thread.currentThread().getName() + ".....else.....obj1.....");
                    }
                }
            }
        }
    }
}

活锁

丈夫和妻子用餐时,需要使用勺子,这时只能有一人持有,也就是说同一时刻只有一个人能够进餐。
但是丈夫和妻子互相谦让,都想让对方先吃,所以勺子一直传递来传递去,谁都没法用餐。

//定义一个勺子,ower 表示这个勺子的拥有者
    static class Spoon {
        Diner owner;//勺子的拥有者
        //获取拥有者
        public String getOwnerName() {
            return owner.getName();
        }
        //设置拥有者
        public void setOwner(Diner diner) {
            this.owner = diner;
        }
        public Spoon(Diner diner) {
            this.owner = diner;
        }
        //表示正在用餐
        public void use() {
            System.out.println(owner.getName() + " use this spoon and finish eat.");
        }
    }
    //定义一个晚餐类
    static class Diner {
        public Diner(boolean isHungry, String name) {
            this.isHungry = isHungry;
            this.name = name;
        }
        private boolean isHungry;//是否饿了
        private String name;//定义当前用餐者的名字
        public String getName() {//获取当前用餐者
            return name;
        }
        //可以理解为和某人吃饭
        public void eatWith(Diner spouse, Spoon sharedSpoon) {
            try {
                synchronized (sharedSpoon) {
                    while (isHungry) {
                        //当前用餐者和勺子拥有者不是同一个人,则进行等待
                        while (!sharedSpoon.getOwnerName().equals(name)) {
                            sharedSpoon.wait();
                            //System.out.println("sharedSpoon belongs to" + sharedSpoon.getOwnerName())
                        }
                        //spouse此时是饿了,把勺子分给他,并通知他可以用餐
                        if (spouse.isHungry) {
                            System.out.println("I am " + name + ", and my " + spouse.getName() + " is hungry, I should give it to him(her).\n");
                            sharedSpoon.setOwner(spouse);
                            sharedSpoon.notifyAll();
                        } else {
                            //用餐
                            sharedSpoon.use();
                            sharedSpoon.setOwner(spouse);
                            isHungry = false;
                        }
                        Thread.sleep(500);
                    }
                }
            } catch (InterruptedException e) {
                System.out.println(name + " is interrupted.");
            }
        }
    }
    public static void main(String[] args) {
        final Diner husband = new Diner(true, "husband");//创建一个丈夫用餐类
        final Diner wife = new Diner(true, "wife");//创建一个妻子用餐类
        final Spoon sharedSpoon = new Spoon(wife);//创建一个勺子,初始状态并由妻子持有
        //创建一个 线程,由丈夫进行用餐
        Thread h = new Thread() {
            @Override
            public void run() {
                //表示和妻子用餐,这个过程判断妻子是否饿了,如果是,则会把勺子分给妻子,并通知她
                husband.eatWith(wife, sharedSpoon);
            }
        };
        h.start();
        //创建一个 线程,由妻子进行用餐
        Thread w = new Thread() {
            @Override
            public void run() {
                //表示和妻子用餐,这个过程判断丈夫是否饿了,如果是,则会把勺子分给丈夫,并通知他
                wife.eatWith(husband, sharedSpoon);
            }
        };
        w.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        h.interrupt();
        w.interrupt();
        try {
            h.join();//join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续;通常用于在main()主线程内,等待其它线程完成再结束main()主线程。
            w.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

饥饿

饥饿是指某一个或者多个线程因为种种原因无法获得所要的资源,导致一直无法执行。
比如它的优先级可能太低,而高优先级的线程不断抢占它需要的资源,导致低优先级线程无法工作

/**
    * 获取一个单例线程池,只有一个线程,任何有序执行,先到先执行
    * 这个线程会保证你的任务执行完成,如果当前线程意外终止,会创建一个新线程继续执行任务
    */
   private  static ExecutorService single= Executors.newSingleThreadExecutor();
   public static class  AnotherCallable implements Callable<String> {
       @Override
       public String call() throws Exception {
           System.out.println("in AnotherCallable");
           return "another- success";
       }
   }
   public static class MyCallable implements Callable<String>{
       @Override
       public String call() throws Exception {
           System.out.println("in MyCallable");
           //因为线程池中只有一个线程,执行下一行代码的时候,需要重新启动一个线程去执行
           //但是唯一的线程已经被new MyCallable();所占用,所以下面一行代码,没有线程,也就无法继续往下执行,线程阻塞(程序死锁)
           Future<String> submit = single.submit(new AnotherCallable());
           return submit.get();
       }
   }
   public static void main(String[] args) throws Exception {
       MyCallable myCallable = new MyCallable();
       Future<String> submit = single.submit(myCallable);
       System.out.println(submit.get());
       System.out.println("over");
       single.shutdown();
   }
1

评论区