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 未満なので待機: デッドロック

宿題の問題の正確な要件が何であるかはわかりませんが、リリースとリクエストの方法を再検討する必要があります。実行可能な解決策が 2 つあります。

  1. リリース メソッドを変更して、MAX_FREE までしかリリースしないが、それでも返されるようにします。
  2. 要求された量のサブセット、notifyAll を解放できるように解放方法を変更し、残りの量を解放できるように待機を再入力します。

また、ExecutionService の使い方が間違っています。ExecutionService はスレッドを作成するものであるため、あなたが行っているようにスレッドを作成する理由はありません。

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

作成しているスレッドは、実際にはスレッドとして「開始」されることはありません。ExecutionService スレッドが MemAlloc*.run() を呼び出す Thread.run() を呼び出すため、まだ機能しています。つまり、t1 スレッドと t2 スレッドは run() 呼び出しを渡すだけで、値を提供しません。

MemAllocRequester と MemAllocReleaser は Runnable であるため、これらを直接 ExecutionService に渡すだけです。

executor.submit(new MemAllocRequester(memoryAllocator));
executor.submit(new MemAllocReleaser(memoryAllocator));
于 2012-11-09T05:31:48.330 に答える