2015-05-18 58 views
-1

请帮助我。此代码可能被阻止在哪里? 我认为它不应该阻止。该线程,该getItem等待, 细节出现在存储中,并通知任何人,如果它从存储获取任何项目。 putItem中的线程,当 它将任何细节放入存储并等待它已满。这样对吗? 我认为不会,因为出现死锁 对不起我的英文。这不是我的母语。同步块。僵局。 Java

public class Storage<E> { 

ArrayList<E> details; 
private Integer limit; //Storage Capacity 
final MonitorObject expectItemObject; //objects for synchronization 
final MonitorObject expectPlaceObject; 

public Storage(Integer limit) 
{ 
    this.limit = limit; 
    expectItemObject = new MonitorObject(); 
    expectPlaceObject = new MonitorObject(); 
    details = new ArrayList<>(limit); 
} 
public Integer getSize() 
{ 
    int detNo=0; 
    synchronized (expectPlaceObject) 
    { 
     synchronized (expectItemObject) { 
      detNo = details.size(); 
     } 
    } 
    return detNo; 
} 
public void putItem(E e) throws InterruptedException 
{ 
    synchronized (expectPlaceObject) 
    { 
     while (getSize().equals(limit)) { //ensure that we have a place 
      expectPlaceObject.wait(); //sleep if storage is full 
     } 
     synchronized (expectItemObject) { //there is no trouble in inners synchronized, as the second is not blocking. 
      details.add(e); 
      expectItemObject.notify(); //if anybody,who expect item, sleep, awake him. 

     } 

    } 

} 
public E getItem() throws InterruptedException 
{ 
    E detail; 
    synchronized (expectItemObject) 
    { 
     while (getSize() == 0) { 
      expectItemObject.wait(); //sleep if storage is empty 
     } 
     synchronized (expectPlaceObject) { 
      detail= details.remove(0); 
      expectPlaceObject.notify(); //if anybody,who expect place sleep, awake him. 
     } 

    } 
    return detail; 
} 
} 
+0

边注:一个症结与锁定;人类在预测会发生什么时非常糟糕。我读了你的代码,并检查了“他是否总是以相同的顺序请求锁?”,并忽略了你正在做的。有时候这些东西很容易,但很多时候却不是。然后,创建一个Java转储并分析它的速度就快很多了。所以我的建议是:学习如何做到这一点;它可以为你节省大量的时间。 – GhostCat

回答

2

putItemgetItem要同步两个不同的OBJETS,expectPlaceObjectexpectItemObject

问题是,您在两种方法中以不同的顺序同步它们。什么都可能发生如下:

  1. 线程A调用putItem和锁expectedItemObject
  2. 同时线程B调用getItem和锁expectedPlaceObject
  3. 接下来两个线程要锁定另一个线程已经锁住了一个对象,导致死锁。

调查死锁的一个好方法是使用jstack来进行进程的线程转储。输出将列出您的死锁。

+0

谢谢!我应该猜测。 – Artem

1

尝试使用这种改变你的getSize()方法:

public Integer getSize() { 
    return details.size(); 
}