1

使用 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;
}

}

该对象通过一个实现可运行的简单包装器访问,并调用任一方法,如下所示。

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 秒,然后两个线程都进入等待状态,即使应该强制执行锁定。

4

1 回答 1

4

问题是两个线程同时达到上限和下限(分别为 50 和 0)。下面的两个示例都突出了死锁。

方案 1

  1. 请求(29) - freePages=21
  2. request(30) - 低于 0 所以等待
  3. release(30) - 超过 50 所以等待:死锁

方案 2

  1. 请求(29) - freePages=21
  2. release(30) - 超过 50 个,请等待
  3. request(30) - 低于 0 所以等待:死锁

我不确定作业问题的确切要求是什么,但您需要重新访问发布和请求方法。我看到了两个可行的解决方案:

  1. 更改释放方法,使其仅释放最多 MAX_FREE 但仍会返回
  2. 更改释放方法,使其可以释放请求数量的子集,notifyAll,重新进入等待,以便可以释放剩余数量。

此外,您有点错误地使用了 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));
于 2012-11-09T05:31:48.330 回答