使用 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 秒,然后两个线程都进入等待状态,即使应该强制执行锁定也是如此。
最佳答案
问题是两个线程同时达到上限和下限(分别为 50 和 0)。下面的两个示例都强调了僵局。
场景一
- 请求(29) - freePages=21
- request(30) - 低于 0,所以等待
- release(30) - 超过 50 所以等待:死锁
场景 2
- 请求(29) - freePages=21
- release(30) - 超过 50 等一下
- request(30) - 低于 0 所以等待:死锁
我不确定作业问题的具体要求是什么,但您需要重新访问发布和请求方法。我看到两个可行的解决方案:
- 更改释放方法,使其最多释放 MAX_FREE 但仍会返回
- 更改释放方法,以便它可以释放所请求数量的子集,notifyAll,重新进入等待状态,以便它可以释放剩余数量。
此外,您在使用 ExecutionService 时有点不对。 ExecutionService 是创建线程的原因,因此您没有理由像现在这样创建线程。
Thread t1 = new Thread(new MemAllocRequester(memoryAllocator));
Thread t2 = new Thread(new MemAllocReleaser(memoryAllocator));
您正在创建的线程实际上永远不会作为线程“启动”。它仍然为您工作,因为 ExecutionService 线程将调用您的 Thread.run(),而 Thread.run() 将调用 MemAlloc*.run()。即,您的 t1 和 t2 线程只是传递 run() 调用,不提供任何值。
您的 MemAllocRequester 和 MemAllocReleaser 是 Runnable,因此只需将它们直接传递到 ExecutionService。
executor.submit(new MemAllocRequester(memoryAllocator));
executor.submit(new MemAllocReleaser(memoryAllocator));
关于java - 两个线程死锁但不明白为什么,用 notifyAll() 释放了锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13301385/