两个线程死锁但看不到原因,用notifyAll()释放锁

时间:2012-11-09 02:45:19

标签: java concurrency monitor

使用JConsole,当2个线程试图修改此对象时,我似乎遇到了死锁情况。

package com.steven.concurrent.assignment2.memoryallocator;
/*
 * This seems to deadlock... cant see why though.
 */
public class MemAllocMonitor implements IMemoryAllocator {

private final int MAX_FREE = 50;
private int freePages = MAX_FREE;

//I think this would work, without even the need for sync blocks.....
// But only in the situaion where i would not have to check the bounds of the updates. If it was just modification, this would be
// fine....
//private volatile int freePages = 50;

public MemAllocMonitor(int pages){
    assert(pages < MAX_FREE);
    this.freePages = pages;
}

public MemAllocMonitor(){

}

@Override
public synchronized void request(int number) {
    if(number < 0)
        throw new IllegalArgumentException();

    while(freePages - number < 0) {
        System.out.println("No space....waiting...");
        try {
            this.wait();                
        } catch (Exception e) {}
    }

        freePages -= number;
        System.out.println("Requested : " + number + " remaining " + freePages);

    this.notifyAll();

}

@Override
public synchronized void release(int number) {
    if(number < 0)
        throw new IllegalArgumentException();

    while(freePages + number > MAX_FREE) {
        System.out.println("page table full....would be " + (number + freePages) );
        try {
            this.wait();                
        } catch (Exception e) {}
    }

    freePages += number;
    System.out.println("Released : " + number + " remaining " + freePages);



    this.notifyAll();

}

@Override
public int getFreePages() {
    return freePages;
}

}

通过实现runnable的简单包装器访问此对象,并调用任一方法,如下所示。

package com.steven.concurrent.assignment2.memoryallocator;

import concurrent.RandomGenerator;
import concurrent.Time;

public class MemAllocRequester implements Runnable, MemoryAllocatorAction{

private IMemoryAllocator memoryAllocator;
private volatile boolean shutdown = false;;

public MemAllocRequester(IMemoryAllocator memAlloc){
    this.memoryAllocator = memAlloc;

}


@Override
public void run() {
    while(!shutdown){
        Time.delay(500);
        memoryAllocator.request(RandomGenerator.integer(0, 30));
    }

}

public void ShutDown(){
    this.shutdown = true;
}

}

package com.steven.concurrent.assignment2.memoryallocator;

import concurrent.RandomGenerator;
import concurrent.Time;

public class MemAllocReleaser implements Runnable, MemoryAllocatorAction{

private IMemoryAllocator memoryAllocator;
private volatile boolean shutdown = false;;

public MemAllocReleaser(IMemoryAllocator memAlloc){
    this.memoryAllocator = memAlloc;

}


@Override
public void run() {
    while(!shutdown){
        Time.delay(500);
        memoryAllocator.release(RandomGenerator.integer(0, 30));
    }

}

public void ShutDown(){
    this.shutdown  = true;
}

}

它是这样开始的......

package com.steven.concurrent.assignment2.memoryallocator;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MemAllocMain {


public static void main(String[] args){

    ExecutorService executor = Executors.newFixedThreadPool(10);


    //IMemoryAllocator memoryAllocator = new MemAllocSemaphore();
    IMemoryAllocator memoryAllocator = new MemAllocMonitor();


    System.out.println("Starting app with " + memoryAllocator.getFreePages() + " pages...");

    Thread t1 = new Thread(new MemAllocRequester(memoryAllocator));
    Thread t2 = new Thread(new MemAllocReleaser(memoryAllocator));

    t1.setName("MEMORY REQUESTER £££££££££££££££££££");
    t2.setName("MEMORY RELEASER £££££££££££££££££££");

    executor.submit(t1);
    executor.submit(t2);


}

}

我已经使用信号量类实现了一个解决方案,但由于某种原因,使用默认的java监控解决方案会导致问题。它运行大约30秒,然后两个线程都进入等待状态,即使应该强制执行锁定。

1 个答案:

答案 0 :(得分:4)

问题是两个线程同时击中上限和下限(分别为50和0)。以下两个例子都突出了僵局。

情景1

  1. request(29) - freePages = 21
  2. 请求(30) - 在0以下等待
  3. 发布(30) - 超过50等等:死锁
  4. 情景2

    1. request(29) - freePages = 21
    2. 发布(30) - 超过50等等
    3. request(30) - 0以下等待:deadlock
    4. 我不确定作业问题的具体要求是什么,但您需要重新审视发布和请求方法。我看到两个可行的解决方案:

      1. 更改发布方法,使其仅释放MAX_FREE,但仍会返回
      2. 更改发布方法,以便它可以释放所请求金额的一部分,notifyAll,重新输入等待,以便它可以释放剩余金额。
      3. 此外,您有点使用ExecutionService错误。 ExecutionService是创建线程的原因,因此没有理由像你一样创建线程。

        Thread t1 = new Thread(new MemAllocRequester(memoryAllocator));
        Thread t2 = new Thread(new MemAllocReleaser(memoryAllocator));
        

        您正在创建的线程实际上永远不会以“线程”的形式“启动”。它仍然适用于您,因为ExecutionService线程将调用您的Thread.run(),它将调用MemAlloc * .run()。即你的t1和t2线程只是传递run()调用并没有提供任何值。

        您的MemAllocRequester和MemAllocReleaser是Runnables,所以只需将它们直接传递到ExecutionService。

        executor.submit(new MemAllocRequester(memoryAllocator));
        executor.submit(new MemAllocReleaser(memoryAllocator));