2013-01-12 69 views
2

我很抱歉,這太長了,看起來太多問了,但如果你能弄清楚什麼是錯誤的一目瞭然,請讓我知道。我不知道這個線程有什麼問題,我想了解多線程

在這個程序中,我嘗試從鍵盤輸入一些單詞(短語),每次取一個令牌並將其分配給一個對象sharedStorer(然後打印指定的值以跟蹤輸入內容,因爲我有一個鏈單詞分開輸入)。這是由一個線程(Retriever類的主題,其implementsRunnable

還有就是class TokenReader另一個線程讀取的sharedStorer值,並打印出來完成。 TokenReader等待輸入Retriever,當Retriever試圖輸入,而TokenReader尚未讀取前一個標記Retriever等待。

我的問題是最後TokenReader等待永久Retriever已完成其任務,因此程序永遠不會終止。

這裏是我用來執行所需任務的所有4個類(和1個接口)。

package Multithreads; 

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class ExerciseTest { 


public static void main(String[] args) { 

    ExecutorService app=Executors.newFixedThreadPool(2); 

    Storer st=new SyncStorer(); 

    System.out.println("Operation performed\t\t Value"); 
    try{ 
    app.execute(new Retriever(st)); 
    app.execute(new TokenReader(st)); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } 
    app.shutdown(); 
} 

} 

package Multithreads; 

public interface Storer { 

public void set(String token); 
public String get(); 
} 

package Multithreads; 

import java.util.NoSuchElementException; 
import java.util.Random; 
import java.util.Scanner; 
import java.util.StringTokenizer; 

public class Retriever implements Runnable { 

private Scanner scanner; 
private String token; 
private String currentToken; 
private Storer sharedStorer; 
private Random rd=new Random(); 
public int tokenLength=0; 

public Retriever(Storer st) { 

    sharedStorer=st; 

} 
public Retriever() { 

} 
@Override 
public void run() { 

    System.out.println("Enter a phrase"); 
    scanner = new Scanner(System.in); 
    token=scanner.nextLine(); 
    StringTokenizer tokenizer=new StringTokenizer(token); 

    while(tokenizer.hasMoreTokens()) 
    { 
     tokenLength++; 
     currentToken=tokenizer.nextToken(); 
     try{ 

     Thread.sleep(10*rd.nextInt(2000)); 
     sharedStorer.set(currentToken); 

     }catch(NoSuchElementException e){ 
      e.printStackTrace(); 

     }catch(InterruptedException e){ 
      e.printStackTrace(); 
     } 
    } 
    System.out.println("Done Inputting The phrase"); 

} 

} 

package Multithreads; 

import java.util.Random; 

public class TokenReader implements Runnable { 

private Random rd=new Random(); 

private Storer sharedStorer; 
Retriever rtr=new Retriever(); 
private int count=rtr.tokenLength; 

public TokenReader(Storer st) { 
    sharedStorer=st; 
} 

@Override 
public void run() { 
String str="null"; 
    int i=0; 
    try { 
     while(i <= count){ 
     Thread.sleep(15*rd.nextInt(2000)); 
     str=sharedStorer.get(); 

     } 
    } catch (InterruptedException e) { 

     e.printStackTrace(); 
    } 

    System.out.println("Consumer done reading"); 
} 


} 

package Multithreads; 

import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class SyncStorer implements Storer { 

private Lock accessLock=new ReentrantLock(); 

private Condition canInput = accessLock.newCondition(); 
private Condition canRead = accessLock.newCondition(); 

private String string="null"; 
private boolean isEmpty=false; 

@Override 
public void set(String token) { 
    accessLock.lock(); 
    try 
    { 
     while(isEmpty){ 
      System.out.println("Retriever waiting"); 
      canInput.await(); 
     } 
     string=token; 
     isEmpty=true; 
     System.out.println("Retriever inputs\t\t "+string); 

     canRead.signal(); 
    }catch(InterruptedException e){ 
     e.printStackTrace(); 
    }finally{ 
     accessLock.unlock(); 
    } 

} 

@Override 
public String get() { 

    accessLock.lock(); 
    try{ 
     while(!isEmpty) 
     {    
      System.out.println("No token to read"); 
      canRead.await(); 
     } 
     isEmpty=false; 
     System.out.println("TokenReader reads\t\t "+string); 


     canInput.signal(); 
    }catch(InterruptedException e) 
    { 
     e.printStackTrace(); 
    }finally{ 
     accessLock.unlock(); 
    } 
    return string; 
} 

} 

回答

8

,導致該應用一直運行下去的問題是日在這是一個無限循環:

while(i <= count){ 
     Thread.sleep(15*rd.nextInt(2000)); 
     str=sharedStorer.get(); 

    } 

因爲你不遞減i。並且你試圖用來打破循環的中斷機制(通過異常!)也被打破了。

Thread.sleep(15*rd.nextInt(2000))行看起來像一個黑客,這樣你可以得到任務的時候被中斷的InterruptedException,但:

  • 睡了一隨機的毫秒數點我想不起來和
  • 只需撥打Thread.interrupted()就簡單多了。

此外,因爲有一個機會,中斷後發生上,你正在等待/測試它的點方法是無論如何也可靠;即在get()呼叫中。如果get()呼叫永遠不會返回,因爲store爲空,並且檢索器已結束......那麼您將等待「永遠」。

還有一個最後的問題。如果您希望執行程序服務中斷工作線程,則需要致電app.shutdownNow() ...


如果我試圖實現這種(使用中斷),我會改變它,這樣getset沒有「吞噬」中斷。如果他們看到中斷,他們應該:

  • 允許(後相關清理)的InterruptedException傳播,或
  • 在異常處理程序重新設置線程的中斷標誌。
+0

對於遲到,我改變並增加了i,因爲您注意到會導致無限循環,後來使用了使用ArrayblockingQueue的Consumer/Producer的方法,因爲我後來在我正在使用的書中找到它,它真的縮小了SyncStorer類中的線條,但問題不在那裏,因爲我後來才意識到它。關於如何讓線程在隨機數毫秒內進入休眠狀態,有助於忽略線程正在執行的時間。 nwy我無法理解你的答案,作爲一個初學者,我不想被困在先進的東西,我打算以後再回來。謝謝 –

相關問題