2013-05-08 47 views
5

當前在GUI中生成一個關鍵事件,然後通過幾個類傳遞給一個在單獨線程中運行的類。線程正在等待關鍵事件,並且在接收到一個關鍵事件時,更改類鏈中的變量將被更改(請參見圖表)。但是在調試過程中變量不會改變。來自線程的另一個類的訪問變量

線程正在訪問的類當然是在它自己的線程中,因爲它是從GUI調用的,這導致我認爲這是一個併發問題。

有沒有辦法解決這個可能使用原子整數或鎖?我已經看到了一些使用同步函數的例子,但是我不能讓它們工作,因爲它們沒有解釋類的需求。 (我的意思是他們給你的代碼做同步,但他們沒有解釋如何使一個類「同步」)。

Diagram of class structure 下面是在E類線程的代碼,可以將線程的對象引用從上方從類接收上述等一類的基準的類設置

private Processor processor; 

    public void run() { 
     while (true) { 
      if (keyevent != null) { 


       keyevent = null; 
       processor.I = 4; 
      } 
     } 
    } 

    public void SetProcessor(Processor processor) { 
     this.processor = processor; 
    } 

調試註釋的擴展。在調試過程中,如果我只調試E類中的線程並逐步完成,代碼將正常運行並處理器。我收到四個值。但是,當我不調試那個線程時,處理器中沒有任何事情發生,這就是爲什麼我認爲這可能是一個併發問題。

使我在Class B和Atomic Integer中訪問的變量,也使一些使用的功能同步。調試環境:(之外仍然dosent功能

代碼在B級從E類稱爲

public void SetI(int value){//also tried using synchronized as well 
     I.set(value); 
    } 

該KeyEvent在GUI類通過的KeyListener產生(whenver一個鍵被按下時觸發),該KeyEvent對象然後通過幾個「滴入」函數傳遞給E類,這些函數只傳遞給下一個類,因此GUI調用processor.setKeyevent(e),處理器然後調用bus.setKeyevent(e)等等直到KeyEvent屬性設置在E類中。

系統初始化後,E類中的線程啓動,is不斷檢查Keyevent屬性的值,一旦KeyEvent不爲null,即它已從GUI(通過其他所有內容)傳遞過來,E類然後在類B中設置整數屬性的值。

發生了什麼當鍵被按下時什麼也沒有發生,應該發生的事情是該整數是類B應該改變,因爲類E,但它不是。由於net beans不允許我一次調試兩個線程,所以它讓我有點尷尬,當我在E類中的線程之外的代碼中放置斷點時,它不起作用,就好像線程沒有運行或者作爲如果它沒有收到keyevent,如果我在線程中放置斷點而不在外面工作,那麼B類中I的值會改變。如果它在調試之外運行,它將無法工作:/

+0

顯示源。 E類的實例如何獲得對B類的引用? – digitaljoel 2013-05-08 20:49:28

+0

你說過「在調試過程中變量沒有改變」。你可以發佈打印調試的代碼和修改變量的代碼(在其他類中)嗎? – KyleM 2013-05-08 20:50:07

+0

發送'ClassB'的對象作爲參數,直到達到'ClassE',也許? – Goodwine 2013-05-08 20:55:02

回答

3

E類不應該直接操作B類中的數據成員。這是各種不好的。但這不是你問題的關鍵。

爲了讓B中的GUI線程看到E中線程所做的更改,您需要使用某種同步控制。通常我會建議使用AtomicInteger,但是你提到了一些swing的東西,所以我假設B類實際上是一個Swing組件。在那種情況下,我發現把東西擺在EDT上是更清潔的,並且讓E有責任在EDT上打電話給B。

這是我的意思。無論如何,我已經消除了C和D級,因爲它們只是傳遞。我也忽略了線程的構建/設置和啓動。我已經刪除了E中的忙碌循環,並用CountDownLatch代替它。

/** 
* Some GUI class, should only be accessed from the EDT 
*/ 
public class B extends JPanel { 

    private int value = 0; 

    private E thatThreadObject; 

    public void setE(E e) { 
     thatThreadObject = e; 
    }  
    public void setValue(int newValue) { 
     value = newValue; 
     System.out.println("Got a new int value: " + value); 
    } 

    public void triggerKeyEvent() { 
     thatThreadObject.keyEvent(); 
    } 
} 

/** 
* Must be thread-safe, as accessed from multiple threads 
*/ 
public class E implements Runnable{ 
    private B thatGuiObject; 
    // Note, latch is only good for one-time use. 
    private final CountDownLatch latch = new CountDownLatch(1); 

    public void setB(B b) { 
     thatGuiObject = b; 
    } 

    public void keyEvent() { 
     // Wake up the waiting thread 
     latch.countDown();    
    } 

    @Override 
    public void run() { 
     try { 
      // Wait for key event forever, better than busy looping 
      latch.await(); 
      // Update B, but it's a Swing component so use EDT 
      EventQueue.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        thatGuiObject.setValue(4); 
       } 
      }); 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     }    
    } 
} 

看一看在Java Concurrency Tutorial

+0

感謝您的幫助。我完全知道,這種結構幾乎違反了所有面向對象範式的法律,然而,儘管我們很難做到這一點,但必須按照客戶的要求這樣做:(再次感謝 – Samishalt 2013-05-09 08:13:00

+0

我在系統中添加了原子整數,運行時仍然沒有正常運行如果我在E類的線程中放置了一個斷點,然後運行調試,那麼一切都可以正常工作,不知道我還能做什麼,因爲不太熟悉Java中的併發性:/ – Samishalt 2013-05-09 18:49:32

+0

你可以在你的問題中增加一些代碼嗎?具體來說就是從E中調用的B中的代碼,以及傳入鍵事件的E中的代碼,以及隨後調用B的代碼 你能澄清一下什麼是不工作嗎?E中的代碼永遠不會得到關鍵事件,B永遠不會被調用,B是被調用的,但值不會改變嗎? – wolfcastle 2013-05-09 19:01:07