2012-05-14 31 views
-1

我在Java中遇到線程問題。 我想編寫一個程序,其中有一個Class的Main類,它有一些類(線程任務)的線程的ArrayList,它只是寫一個字母和數字。 Object Main只是從ArrayList中喚醒一個線程,讓它做一些事情,而同一個對象(Main)睡眠另一個線程。 但是,即使我將Main.ACTIVE更改爲false,但仍然存在一個問題,它並不會終止所有線程,而是隨機的,我只想讓它們結束並寫入:正確結束java中的線程

我在說goodbay +字符 - 某事像那

public class Main extends Thread { 
    ArrayList<Thread> threads; 
    static boolean ACTIVE = true; 
    public Main() { 
     super(); 
     threads = new ArrayList<Thread>(); 
    } 

    public void run(){ 

     Object monitor = new Object(); 
     for (int i = 0; i <= 5; i++) { 
      threads.add(new Thread(new Task(i + 65, monitor))); 
     } 

     long cT = System.currentTimeMillis(); 
     for (int i = 0; i < threads.size(); i++) { 
      threads.get(i).start(); 
     } 
     System.out.println("BEFORE synchronized(monitor)"); 
     synchronized(monitor){ 
      while (System.currentTimeMillis() - cT < 1000) { 
       try{ 
        monitor.notify(); 
        Thread.sleep(50); 
        monitor.wait(); 
       } catch(Exception e){ 
        e.printStackTrace();} 
       } 
       System.out.println("BEFORE ACTIVE= FALSE and after WHILE in Main"); 
       ACTIVE = false; 
       for(int i = 0; i < threads.size(); i++){ 
        System.out.println(threads.get(i).getState()); 
       } 
      } 
      System.out.println("LAST COMMAND IN MAIN"); 
     } 
    } 

    public static void main(String[] args) { 
     new Main().start(); 
     //new Thread(new Task(65)).start(); 
    } 
} 

,任務類

public class Task implements Runnable { 
    int nr; 
    char character; 
    Object monitor; 

    public Task(int literaASCII, Object monitor) { 
     this.nr = 0; 
     this.monitor = monitor; 
     character = (char) (literaASCII); 
    } 

    @Override 
    public void run() { 
     synchronized (monitor) { 
      while (Main.ACTIVE) { 
       try { 
        System.out.println("ENTERING WHILE IN TASK"); 
        monitor.wait(); 
        System.out.print(nr + "" + character + ", "); 
        nr++; 
        int r = (int) ((Math.random() * 50) + 50); // <500ms,1000ms) 
        Thread.sleep(r); 
       } catch (Exception e) {e.printStackTrace();} 
       monitor.notify(); 
       System.out.println("YYYYYYYYY"); 
      } 
      System.out.println("AFTER WHILE IN Task"); 
     } 
     System.out.println("I am saying goodbye " + character); 
    } 
} 
+1

你爲什麼要用手來實現線程池?在'Executors'類中實現了一堆預定義的線程池。 – JesperE

+1

如果適用,您應該添加作業標籤(這似乎是這種情況)。 – assylias

+0

不是我的作業這是我的朋友,我想教他簡單的線程管理。我喜歡其他工具來做到這一點。 – Yoda

回答

0

現在naswer是

0A,0B,0C,0D,0E,0F,1A,1B,1C,1D,1E,1F,等待 WAITING WAITING WAITING WAITING WAITING LAST COMMAND IN主要

我開始線程

import java.util.ArrayList; 

public class Main extends Thread { 
ArrayList<Thread> threads; 
volatile static boolean ACTIVE = true; 
public Main() { 
    super(); 
    threads = new ArrayList<Thread>(); 
} 

public void run(){ 

Object monitor = new Object(); 
for (int i = 0; i <= 5; i++) { 
    threads.add(new Thread(new Task(i + 65, monitor))); 
} 

long cT = System.currentTimeMillis(); 
for (int i = 0; i < threads.size(); i++) { 
    threads.get(i).start(); 
} 
try{Thread.sleep(50);}catch(Exception e){e.printStackTrace();} 
// System.out.println("BEFORE synchronized(monitor)"); 
synchronized(monitor){ 
    while (System.currentTimeMillis() - cT < 1000) { 
     try{ 

    monitor.notify(); 
    Thread.sleep(500); 

    monitor.wait();}catch(Exception e){e.printStackTrace();} 
    } 
    // System.out.println("BEFORE ACTIVE= FALSE and after WHILE in Main"); 
    ACTIVE = false; 
    for(int i = 0; i < threads.size(); i++){ 
     System.out.println(threads.get(i).getState()); 
    } 


} 
System.out.println("LAST COMMAND IN MAIN"); 

    } 


    public static void main(String[] args) { 
    new Main().start(); 
    //new Thread(new Task(65)).start(); 

} 

} 

,任務

後增加睡眠
public class Task implements Runnable { 
int nr; 
char character; 
Object monitor; 

public Task(int literaASCII, Object monitor) { 
    this.nr = 0; 
    this.monitor = monitor; 
    character = (char) (literaASCII); 
} 

@Override 
public void run() { 
    synchronized (monitor) { 
     while (Main.ACTIVE) { 
      try { 
//    System.out.println("ENTERING WHILE IN TASK"); 
       monitor.wait(); 
       System.out.print(nr + "" + character + ", "); 
       nr++; 
       int r = (int) ((Math.random() * 50) + 50); // <500ms,1000ms) 

       Thread.sleep(r); 
      } catch (Exception e) {e.printStackTrace();} 
      monitor.notify(); 
    //  System.out.println("YYYYYYYYY"); 
     } 
     System.out.println("AFTER WHILE IN Task"); 
    } 
    System.out.println("I am saying goodbye " + character); 
} 

}

3

你的問題是需要ACTIVE應該被標記爲volatile首發。任何由多個線程共享的變量需要以某種方式爲​​或標記爲volatile,以便它在讀取和寫入時會有內存障礙。

你可以從布爾的角度做的另一件事是使用AtomicBoolean類而不是volatile boolean

取而代之的是static volatile boolean,你可能反而認爲有volatile boolean每個Task對象,以便Main擁有單獨的任務更爲精細的控制,你使用的是static「全局」變量。您甚至可以添加task.shutdown()方法來設置活動標誌。

最後,正如@duffmo提到的那樣,如果您始終只想運行一個線程,則應始終考慮使用其中一個線程池ExecutorService。像Executors.newFixedThreadPool(1)。但我無法確定你是否只需要一個線程。如果您使用的ExecutorService然後main只想做:

ExecutorService threadPool = Executors.newFixedThreadPool(1); 
List<Future> futures = new ArrayList<Future>(); 
for (int i = 0; i <= 5; i++) { 
    // the monitor would not be needed 
    threadPool.submit(new Task(i + 65)); 
} 
threadPool.shutdown(); 
for (Future future : futures) { 
    // this waits for the working task to finish 
    future.get(); 
} 

但是如果你需要你的後臺任務停止和啓動喜歡它目前正在與monitor做那麼這種模式可能無法正常工作。

+0

我不能使用執行程序隊列,鎖等。這是被禁止的。 我改變ACTIVE到易失性但效果保持不變 0A,0B,0C,0D,0E,1A,1B,1C,1D,1E,2A,2B,2C,2D,2E,WAITING WAITING WAITING WAITING WAITING BLOCKED 最後一個命令在主 後在任務 我說再見F – Yoda

+0

我有點驚訝@Robert它運行在所有。僅僅因爲你調用'start()'並不意味着線程會立即運行,所以很有可能'main'是第一個在顯示器上同步的。由於沒有人在等待,所以第一個「通知」主程序不會執行任何操作。它會「睡覺」然後「等待」。然後所有分叉的線程將運行到'wait'調用,程序將掛起。沒有人留下來叫'通知'。我想這取決於有多少線程能夠快速啓動,並將'main'打入'wait()'。在開始線程後嘗試在'main'中進行睡眠。 – Gray

+0

現在的答案是永遠 0A,0B,0C,0D,0E,0F,1A,1B,1C,1D,1E,1F,等待 WAITING WAITING WAITING WAITING WAITING 最後一個命令主 我我將代碼添加到頁面的答案中 – Yoda

4

我建議你看看java.util.concurrent包中更現代的併發類,尤其是ExecutorService。並閱讀「實踐中的Java併發性」。