2014-03-25 165 views
2

我只是寫了一些代碼來測試多線程如何同步,但我無法得到我的預期結果。代碼可以啓動3個線程,但只有一個線程來處理共享資源。什麼是錯的用我的代碼。java同步多線程問題

class ThreadDemo1{ 
    public static void main (String[] args){ 
     MultiThread tt = new MultiThread(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
    } 
} 
class MultiThread implements Runnable { 
    int tickets = 100; 
    Object _lock = new Object(); 
    public void run() { 
    System.out.println(Thread.currentThread().getName()); 
    synchronized(_lock) { 
     while (true) { 
     if (tickets>0) { 
      try { 
      Thread.sleep(10); 
      } catch (Exception e) {} 
      System.out.println(Thread.currentThread().getName() + " is selling "+tickets--); 
     } 
     } 
    } 
    } 
} 
+0

鎖必須是靜態 –

+0

你有一些古怪的格式有...採用更標準的格式化會幫你寫更清晰的代碼,我們理解你的代碼。例如,你原來的帖子中遺漏了大括號,這完全不清楚。 – yshavit

回答

2

你正在睡覺,而按住鎖。如果你打算這麼做,沒有理由多線程化。

public void run() { 
    System.out.println(Thread.currentThread().getName()); 
    while(tickets > 0) { 
     synchronized(_lock) { 
      if (tickets > 0) { 
       System.out.println(Thread.currentThread().getName() + " is selling " + tickets--); 
      } 
     } 
     try { 
      Thread.sleep(10); 
     } catch (Exception e) { 
     } 
    } 
} 

我猜0123,是你的處理佔位符。如果可能的話,你應該在synchronized塊內執行檢查和減量操作,但是你需要在它之外進行冗長的處理。

爲了使鎖和多線程能夠爲您做任何有用的事情,您必須確保​​代碼儘可能少的時間,因爲這是一次只能由一個線程運行的代碼。

在你的代碼中,唯一沒有有效單線程的是你的第一個System.println


僅供參考,考慮到這一點,如果你可以讓你的打印語句準確,但有可能失靈,這將是更好的有:

public void run() { 
    System.out.println(Thread.currentThread().getName()); 
    while(tickets > 0) { 
     int oldTickets = 0; 
     synchronized(_lock) { 
      if (tickets > 0) { 
       oldTickets = tickets--; 
      } 
     } 
     if(oldTickets > 0) { 
      System.out.println(Thread.currentThread().getName() + " is selling " + oldTickets); 
      try { 
       Thread.sleep(10); 
      } catch (InterruptedException e) { 
      } 
     } 
    } 
} 
+0

我因爲暗示鎖定對象變爲靜態而被罵。也可以將鎖對象傳遞給每個Runnable以同步。我感到不得不防止別人被罵。:) – mttdbrd

+0

@mttdbrd,我的壞。見編輯的答案。 –

0

[1]首先,在您的發佈代碼中有幾個不好的練習/錯誤:

(1)鎖定對象最好是單身。你可以使用一個靜態字段對象或類本身(由於只有一個類在存儲器中)

Object _lock = new Object(); 
private static final Object _lock = new Object(); 

(2)將while(true) {...}出同步塊的。在你的代碼中,如果第一個線程獲得鎖定,它將處理所有票據並且不會停止。 應該讓每個線程都嘗試在循環的每次迭代中獲得Lock。

(3)對於Thread.sleep(10),我想你的意思是線程正在做一些繁重的工作。但將這種代碼放入同步塊(或另一個名稱:關鍵區域)不是一個好習慣。因爲一次只有一個線程可以訪問同步塊。你的代碼行爲就像是一個單線程程序,因爲其他線程必須等到當前正在運行的線程完成其工作。

請參見下面的代碼:

public class ThreadDemo1 { 
    public static void main(String[] args) { 
     MultiThread tt = new MultiThread(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
     new Thread(tt).start(); 
    } 
} 

public class MultiThread implements Runnable { 
    private static int tickets = 100; 
    private static final Object _lock = new Object(); 

    public void run() { 
     System.out.println(Thread.currentThread().getName()); 
     while (tickets > 0) { 
      try { 
       synchronized (_lock) { 
        if (tickets > 0) { 
         System.out.println(Thread.currentThread().getName() + " is selling " + tickets--); 
        } 
       } 
       Thread.sleep(10); 
      } catch (Exception e) { 
      } 
     } 
    } 
} 

[2]第二,如果你只是想線程在採摘門票同步。嘗試使用Atomic*類而不是同步塊,它是無鎖,並會帶來更好的性能。例如:

import java.util.concurrent.atomic.AtomicInteger; 

public class MultiThreadAtomic implements Runnable { 
    private static AtomicInteger tickets = new AtomicInteger(100); 

    public void run() { 
     System.out.println(Thread.currentThread().getName()); 
     int ticketsRemaining = 0; 
     while ((ticketsRemaining = tickets.getAndDecrement()) > 0) { 
      System.out.println(Thread.currentThread().getName() + " is selling " + ticketsRemaining); 
      try { 
       Thread.sleep(10); 
      } 
      catch(InterruptedException ie) {} 
     } 
    } 
}