2017-09-22 59 views
0

我已經對java線程編碼進行了測試,但是我有一些基本問題。經過幾個小時的嘗試和搜索,我決定嘗試一下!無法通知鎖定

我不明白爲什麼我的等待仍然鎖定即使我的通知:

在這裏你可以找到我的代碼:

public class Mymain { 

    public static void main(String[] args) { 

     for(int i=0;i<100;i++){ 
      new ThreadClass(i).start();  
     } 
    } 
} 

public class ThreadClass extends Thread { 
    static boolean ok = false; 
    int id; 

    public ThreadClass(int i) { 
     id = i; 
    } 

    public void run() { 
     System.out.println("Thread start " + id); 
     Last.toDo(id); 
     if (id == 5) 
      try { 
       waiting(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     if (id != 5) 
      awaking(); 

     System.out.println("thread end " + id); 
    } 

    private synchronized void awaking() { 
     // TODO Auto-generated method stub 
     if (ok) { 
      System.out.println("i'm " + id + " and i'm Awaking 5"); 
      ok = false; 
      notify(); 
      System.out.println("I did the notify and i'm " + id); 
     } 
    } 

    private synchronized void waiting() throws InterruptedException { 
     System.out.println("Sleeping"); 
     ok = true; 
     wait(); 
     System.out.println("Awake 5"); 
    } 
} 

Result

然後開始循環,或者去在死鎖不能確定..它應該只是停止與ID = 5的線程,然後下一個線程應重新啓動ID = 5 ..但線程5從未醒來後通知...

在結果中,你可以看到我有2個線程試圖喚醒線程5和螺紋5的自啓動^^

+0

你能告訴我們你的輸出是什麼,它應該是什麼? –

+0

你可以把它放在你的問題中,以便格式化以便於分析嗎? –

+0

@WarrenDew完^^ – JustMe

回答

-1

看我做你的代碼的一些變化:

  1. 你不能只是notify(),你會通知this。你不能只是wait(),你會永遠等下去。你必須在Object上使用這些函數,所以我添加了一個Integer對象(只是爲了向你展示 - 你必須選擇正確的對象)。
  2. 你喲​​和static synchronized之間的瞭解。快速搜索會導致你一個完美的答案。
  3. 爲什麼功能waiting()被同步?只有線程號碼5調用它。
  4. 當調用一個Object.notify()/Object.wait(),必須聲明在對象同步塊。

下面是一些代碼:

public class Threads { 
    public static void main(String[] args) { 
     Integer intObject = new Integer(0); 
     for(int i=0;i<100;i++){ 

      new ThreadClass(i, intObject).start();  
     } 
    } 
} 
class ThreadClass extends Thread { 
    static boolean ok = false; 
    int id; 
    Integer intObject; 
    public ThreadClass(int i, Integer intObject) { 
     id = i; 
     this.intObject = intObject; 
    } 

    public void run() { 
     System.out.println("Thread start " + id); 
     //Last.toDo(id); 
     if (id == 5) 
      waiting(); 
     else 
      awaking(this); 

     System.out.println("thread end " + id); 
    } 

    private static synchronized void awaking(ThreadClass t) { 
     if(ok) { 
      System.out.println("i'm " + t.id + " and i'm Awaking 5"); 
      ok = false; 
      synchronized (t.intObject) { 
        t.intObject.notify(); 
       } 
      System.out.println("I did the notify and i'm " + t.id); 
     } 
    } 
    private void waiting(){ 
     System.out.println("Sleeping"); 
     ok = true; 
     synchronized (intObject) { 
      try { 
       intObject.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     System.out.println("Awake 5"); 
    } 
} 
+0

泰的回答很明確^^現在我知道了^^ – JustMe

+1

這將是確定的,不同之處在於使用整數鎖定是一個可怕的想法。這不是需要讓示例工作。 –

+0

是的,我寫了它,只是爲了演示如何與一個對象同步工作 – Yinon

0

的問題是,你不打電話通知()對同一對象總是要等着那你打電話給wait()。特別是,線程5本身正在調用wait(),但例如,線程8正在調用notify()而不是線程5.結果,線程5從未收到通知。

此外,您需要使ok變量volatile確保當一個線程設置它時,其他線程可以看到更改。這不會在這種特殊情況下造成問題,但在其他情況下可能會導致問題。

+0

我走到爲此太(第3行),但我不明白我應該怎麼辦通知線程5.這可能是一些基本的東西我我不理.. ^^ 泰的幫助:d – JustMe

+0

一這樣做的方法是用易變的Object變量替換「ok」變量。你會檢查nonnull而不是true,並且線程5將創建該對象並等待它。其他線程會通知它是否在那裏。 –

+0

是啊,我得到了它TY所有^^ – JustMe

0

我不明白爲什麼我的等待仍然鎖定即使我的通知:

等待並使用同一個對象實例通知工作。如果你具有例如:

String x1 = "..."; 
String x2 = "..."; 

和線#1的作用:

synchronized (x1) { x1.wait(); } 

和線#2,那麼做:

synchronized (x2) { x2.wait(); } 

那麼線程#1仍然會等待,因爲通知僅限於x2。在您的示例中,由於您使用的是方法同步,因此ID爲5的線程正在等待其自己的ThreadClass實例。然後當其他線程調用awaking()時,他們也調用了ThreadClass的實例的通知。如果你想讓線程#5看到另一個線程的通知,那麼他們應該共享一個鎖定對象。

也許是這樣的:

final Object lock = new Object(); 
for (int id = 0; id < 100; id++){ 
     new ThreadClass(id, lock).start();  
} 
... 
public class ThreadClass extends Thread { 
    private final Object lock; 
    ... 
    public ThreadClass(int id, Object lock) { 
     this.id = id; 
     this.lock = lock; 
    } 
    ... 
    private void awaking() { 
     ... 
     synchronized (lock) { 
      lock.notify(); 
     } 
     ... 
    } 
    private void waiting() throws InterruptedException { 
     ... 
     synchronized (lock) { 
      lock.wait(); 
     } 
     ... 
    } 
} 
+0

泰的回答很明確^^現在我知道了^^ – JustMe

0

爲什麼你不使用notifyAll的()方法?當你調用通知(),這意味着只有一個線程將狀態從等待可運行改變,但有可能是情況下,當你這是在排隊等候以及多個線程和其他線程,他們將不會收到此通知。在我看來,最好使用notifyAll。

+0

不要這麼認爲^^我解決了建議從其他成員^^ – JustMe

+0

這篇文章沒有準確回答這個問題。如果線程不使用相同的鎖,則它們調用的方法無關緊要。 –