死锁案例

Java 中的死锁案例

synchronized 死锁

线程 thread1 先获取锁 locka,然后在同步块里嵌套竞争锁 lockb。而线程 thread2 先获取锁 lockb,然后在同步块里嵌套竞争锁 locka。

package com.app.test;

import org.apache.poi.util.SystemOutLogger;

public class SyncDeadLock{
    private static Object locka = new Object();
    private static Object lockb = new Object();

    public static void main(String[] args){
        new SyncDeadLock().deadLock();
    }

    private void deadLock(){
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (locka){
                    try{
                        System.out.println(Thread.currentThread().getName()+" get locka ing!");
                        Thread.sleep(500);
                        System.out.println(Thread.currentThread().getName()+" after sleep 500ms!");
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" need lockb!Just waiting!");
                    synchronized (lockb){
                        System.out.println(Thread.currentThread().getName()+" get lockb ing!");
                    }
                }
            }
        },"thread1");

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lockb){
                    try{
                        System.out.println(Thread.currentThread().getName()+" get lockb ing!");
                        Thread.sleep(500);
                        System.out.println(Thread.currentThread().getName()+" after sleep 500ms!");
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" need locka! Just waiting!");
                    synchronized (locka){
                        System.out.println(Thread.currentThread().getName()+" get locka ing!");
                    }
                }
            }
        },"thread2");

        thread1.start();
        thread2.start();
    }
}

异常发生时未正确释放锁

package com.app.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDeadDemo {

    public static void main(String[] args){
        final DeadLockBean deadLockBean = new DeadLockBean();
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    deadLockBean.productDeadLock();
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }
        },"threadA");
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(310);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    deadLockBean.productDeadLock();
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }
        },"threadB");
        threadA.start();
        threadB.start();
        try {
            System.out.println("main线程即将被join");
            threadA.join();
            threadB.join();
            System.out.println("main线程从join中恢复");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static class DeadLockBean{
        private Lock lock = new ReentrantLock();
        public void productDeadLock() throws Throwable {
            System.out.println(Thread.currentThread().getName() + "   进入了方法!");
            lock.lock();
            try{
                System.out.println(Thread.currentThread().getName() + "   已经执行了!");
                throw new Throwable("人为抛出异常Throwable");//关键代码行1,
                //throw new Exception("人为抛出异常Exception");//关键代码行2,不会死锁,会在catch(Exception e中被捕获),嵌套lock.unlock()并释放
            }catch(Exception e){
                System.out.println(Thread.currentThread().getName()+"   发生异常catch!");
                //lock.unlock();//关键代码行3,不建议在这里释放,假如发生【关键代码行1】会产生死锁
            }finally{
                System.out.println(Thread.currentThread().getName()+"   发生异常finally!");
                lock.unlock();//关键代码行4,无论发生何种异常,均会释放锁。
            }
            //lock.unlock();//关键代码行5,假如发生不能捕获异常,将跳出方法体,不执行此处
            System.out.println(Thread.currentThread().getName() + "   tryCatch外释放锁!");
        }
    }
}

Executor Saturation Deadlock | 线程饥饿死锁

在线程池中任务如果依赖其他任务的执行,那么就可能出现死锁。对于单 worker 线程的 Executor,如果在一个已经被提交的任务中提交另一个任务到 Executor 中就会发生死锁。

class Task implements Runnable {
  private final ExecutorService executorService;

  public Task(ExecutorService executors) {
    this.executorService = executors;
  }

  @Override
  public void run() {
    System.out.println("Thread enter: " + Thread.currentThread().getName());
    Task2 task2 = new Task2();

    // 在任务中嵌套执行任务,由于线程池大小只有1,所以该线程永远不会被执行,而正在执行的线程也一直无法返回,这就照成了saturation deadlock
    Future<Boolean> future = executorService.submit(task2);
    try {
      Boolean aBoolean = future.get();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
  }
}

class Task2 implements Callable<Boolean> {

  @Override
  public Boolean call() throws Exception {
    SleepUtil.sleepSeconds(10);
    return true;
  }
}

如果要避免 Saturation Deadlock 的方法就需要尽量提交独立的任务不相互依赖的任务。

上一页