65.9K
CodeProject 正在变化。 阅读更多。
Home

死锁解决方案

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2011年11月6日

公共领域

2分钟阅读

viewsIcon

25369

downloadIcon

166

使用 ExecutorService 和 LiveLockSolution 接口解决死锁问题

Java 并发问题简介

Java,凭借其并发 API,为死锁问题提供了良好的解决方案:使用 java.util.concurrent.locks 接口及其实现,例如 ReentrantLock 类;而对于解决活锁问题,在线文档并不多。
饥饿是与并发相关的另一个问题,请参阅参考资料部分以深入了解。

什么是活锁

活锁的定义,来自 教程:并发

一个线程通常是对另一个线程的动作做出反应。如果另一个线程的动作也是对另一个线程的动作做出反应,那么就可能导致活锁。与死锁一样,活锁线程无法继续前进。但是,这些线程并没有被阻塞——它们只是太忙于相互响应而无法恢复工作。这类似于两个人试图在走廊里互相让路:Alphonse 向左移动让 Gaston 通过,而 Gaston 向右移动让 Alphonse 通过。看到他们仍然互相阻碍,Alphone 向右移动,而 Gaston 向左移动。他们仍然互相阻碍,所以……

我的解决方案

我提出的解决方案使用了 java.util.concurrent.ExecutorService 接口和由我创建的 LiveLockSolution 接口。

如何使用 LiveLockSolution 接口

使用 LiveLockSolution,我将记住在用于数据并发的类中编写一个方法来解决活锁问题。

public interface LiveLockSolution {
    public void liveLockSolution();
}

这是使用锁并实现 LiveLockSolutionProduct 类。

public class Product implements LiveLockSolution{
    private int quantity;
    private boolean endLoop;
    private ReentrantLock lock;
    private Condition cond;
    
    public Product(ReentrantLock lock) {
        this.endLoop = false;
        this.quantity = 0;
        this.lock = lock;
        this.cond = lock.newCondition();
    }
    
    public void produce() {
        lock.lock();
        try {
            this.quantity++;
            System.out.println("Q:" + this.quantity);
            cond.signalAll();
        } finally {
            lock.unlock();
        }        
    }
    
    /**
     * It consumes a product, if there isn't a product wait
     */
    public void consume() {
        lock.lock();
        try {
            while(this.endLoop == false && this.quantity == 0) {
                cond.await();
            }
            if(this.endLoop == false) { 
                this.quantity--;
                System.out.println("Q:" + this.quantity);
            }
            cond.signalAll();
        } catch(Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * To ending all waiting threads that use Product 
     */
    @Override
    public void liveLockSolution() {
        lock.lock();
        try {
            this.endLoop = true; //it says to consume to don't wait any more
            cond.signalAll();
        } finally {
            lock.unlock();
        }
    }

Consumer Productor 类现在包含在 zip 文件中。

如何使用 ExecutorService 接口

ExecutorService 接口是主代码中的执行者(参见下一个示例):使用 awaitTermination 方法,在停止所有线程后,我们知道执行器池中是否有正在运行的线程,因此使用 liveLockSolution 来解决活锁问题。

 public static void main(String[] args) {
    try {
        ReentrantLock lock = new ReentrantLock();
        Product obj = new Product(lock);
        Consumer cons = new Consumer(obj);
        Consumer cons2 = new Consumer(obj);
        Producer prod = new Producer(obj);
        
        System.out.println("Start concurrency\n\n");

        ExecutorService es = Executors.newCachedThreadPool();
    
        //executes threads
        es.execute(cons);
        es.execute(cons2);
        es.execute(prod);
        
        //lets execute threads for a second
        Thread.sleep(1000); 
        
        //stops the threads
        prod.stop();
        cons.stop();
        cons2.stop();
        
        //to showdown the executor
        es.shutdown(); 
        //waiting running threads
        while(es.awaitTermination(100, TimeUnit.MILLISECONDS) == false) {
            System.out.println("Waiting threads closing");
            obj.liveLockSolution(); //solve livelock
        }
        System.out.println("Concurrency end");

    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

就这样,各位!

参考文献

历史

  • 首次发布:2011 年 11 月
© . All rights reserved.