2011-04-16 77 views
0

我有下面的代碼試樣片,問題的同步

public class test implements Runnable{ 

    public void run() 
    { 
    synchronized(this) 
    { 
     for(int i=0;i<10000;i++) 
      System.out.println(i); 
    } 
    } 
    public static void main(String args[]) throws Exception 
    { 
    Thread t=new Thread(new test()); 
    t.start(); 

    //Thread.sleep(100); 
    t.suspend(); 
    System.out.println("Hi"); 
    } 
} 

我有以下的要求,當線程被掛起它必須執行該循環的所有迭代而不會掛起。我覺得同步是爲了這個目的,但它沒有解決問題。當我掛起一個線程,如果它在一個同步塊中,那麼它必須在塊被執行後才被掛起。什麼java結構可以用於這個?

+0

注意的可能性Thread.suspend ()已被棄用。 http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#suspend() – 3urdoch 2011-04-16 19:52:44

回答

0

在Java中,當一段代碼位於​​塊中時,一次只能有一個線程執行此塊。爲了暫停後,才完成了synchronized塊,只是同步在同一個變量線程:

public class Test implements Runnable { 
    public void run() { 
     synchronized(this) { 
      // some work 
     } 
    } 

    public static void main(String args[]) throws Exception { 
     Test target = new Test(); 
     Thread t = new Thread(target); 
     t.start(); 

     synchronized(target) { 
      t.suspend(); 
     } 
     System.out.println("Hi"); 
    } 
} 

注意,在run()和兩個塊main()了相同的變量(的Test實例)同步。現在main()中的同步塊中的代碼只有在run()中的工作完成後纔會執行。

(但是請注意,這裏存在一些競爭條件:你不能保證t.start()run()代碼將實際的代碼main()下一行之前執行)

+0

雖然這確實起作用,但爲併發控制掛起線程並不是很好的線程化設計,而且天生就容易出現僵局。請參閱http://download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html – mdma 2011-04-16 20:19:30

+0

@mdma我同意這很糟糕。我不想質疑設計,而是提供一個可行的解決方案。 – pajton 2011-04-16 20:24:07

+0

當然,我自己做了幾次同樣的事!只是想讓OP在生產系統中使用Thread.suspend()的時候意識到這一點。 – mdma 2011-04-16 20:27:05

0

suspend()暫停線程的執行身在何方它是。從程序代碼執行此操作通常不是一個好主意,因爲該線程仍然會保留任何監視器,鎖,資源等。

而是使用同步原語,當您不希望它時阻塞該線程執行。例如,信號量可以用來使一個線程等待:

public class test implements Runnable{ 

final Semaphore semaphore = new Semaphore(); 

public void run() 
{ 
    synchronized(this) 
    { 
     for(int i=0;i<10000;i++) 
      System.out.println(i); 
     semaphore.acquire(); // possibly block on the semaphore 
     semaphore.release(); // release our lock, we don't need it anymore 
    }  
} 

public void suspend() 
{ 
    semaphore.acquire(); 
} 

public void resume() 
{ 
    semaphore.release(); 
} 
} 

public static void main(String args[]) throws Exception 
{ 
    Test test = new test()); 
    Thread thread = new Thread(test); 
    thread.start(); 

    // at some point in the future you want to pause execution 
    test.suspend(); 

    // hi will either appear before all of Test's output, or after. but not inbetween. 
    System.out.println("Hi"); 

    test.resume(); 
} 

您還可以使用鎖和Condition來達到同樣的事情,但它稍微是更多的代碼,所以我們用信號燈的位置,以保持它的簡單。

通過不直接掛起線程,但阻止它,而不是,你打開使用執行人,線程池和其他類型的線程管理(例如ForkJoinPool,SwingWorker類等)