2016-11-22 27 views
1

我想一次調用一個線程調用swing方法的一些信息。我的JAVA代碼線程是否安全,因爲代碼僅由一個線程調用?

編輯: 我使用Java 7

我看到了以下主題:

Thread Safety of JTextArea.append

我developped一個小型Swing應用程序。

這是我的主類,它是一個線程安全類。 我調用SwingUtilities.invokeLater方法使它成爲線程安全類。

MainClass:

package swingex; 

import javax.swing.SwingUtilities; 

public final class MainClass extends Thread { 

    public static void main(String[] _args) { 
     SwingUtilities.invokeLater(new MainClass()); 
    } 

    @Override 
    public void run() { 
     new MainWindow(); 
    } 
} 

這裏是一個類從JFrame中繼承。 我在內容窗格中放置了一個文本區域和一個按鈕。

主窗口:

package swingex; 

import java.awt.Dimension; 

import javax.swing.BoxLayout; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 

public final class MainWindow extends JFrame { 

    private JTextArea textArea = new JTextArea(32,32); 

    //AddText inherits from Thread class 
    private AddText thread = new AddText(textArea); 

    public MainWindow() { 
     JPanel panel_ = new JPanel(); 
     panel_.setLayout(new BoxLayout(panel_, BoxLayout.PAGE_AXIS)); 
     JScrollPane scr_ = new JScrollPane(textArea); 
     scr_.setPreferredSize(new Dimension(128, 128)); 
     panel_.add(scr_); 
     //The button is used for adding rows in the text area 
     JButton button_ = new JButton("Add rows"); 
     //Adding the event 
     button_.addActionListener(new AddTextEvent(this)); 
     panel_.add(button_); 
     setContentPane(panel_); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     pack(); 
     setVisible(true); 
    } 

    //Called by actionPerformed method 
    public void setText() { 
     if (thread.isAlive()) { 
      //prevent from setting the text area by multi threading 
      return; 
     } 
     //For avoiding issues, the text area is affected by less than two threads. 
     thread = new AddText(textArea); 
     thread.start(); 
    } 
} 

點擊按鈕使睡在螺紋而有5秒,然後該線程添加200行到文本區。 AddText:

package swingex; 

import java.awt.Rectangle; 

import javax.swing.JTextArea; 
import javax.swing.text.BadLocationException; 

public final class AddText extends Thread { 

    private JTextArea textArea; 

    public AddText(JTextArea _textArea) { 
     textArea = _textArea; 
    } 

    @Override 
    public void run() { 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException _0) { 
      _0.printStackTrace(); 
     } 
     //Only one thread can access the code 
     for (int i = 0; i < 200; i++) { 
      textArea.append("Text"+i+"\n"); 
     } 
     int endPosition_ = textArea.getDocument().getLength(); 
     Rectangle bottom_; 
     try { 
      bottom_ = textArea.modelToView(endPosition_); 
      textArea.scrollRectToVisible(bottom_); 
     } catch (BadLocationException _0) { 
      _0.printStackTrace(); 
     } 
    } 
} 

這個類實現的ActionListener,它用於點擊按鈕。

AddTextEvent:

package swingex; 

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

public final class AddTextEvent implements ActionListener { 

    private MainWindow window; 

    public AddTextEvent(MainWindow _window) { 
     window = _window; 
    } 

    @Override 
    public void actionPerformed(ActionEvent _e) { 
     window.setText(); 
    } 

} 

預先感謝您。

編輯2:我的「新主題」類是以下之一:(其他類保持不變的)

package swingex; 

import java.awt.Rectangle; 

import javax.swing.JTextArea; 
import javax.swing.SwingWorker; 
import javax.swing.text.BadLocationException; 

/**Now the class AddText inherits from SwingWorker*/ 
public final class AddText extends SwingWorker<Void, Void> { 

    private JTextArea textArea; 

    public AddText(JTextArea _textArea) { 
     textArea = _textArea; 
    } 


    /**The equivalent in the class Thread*/ 
    public void start() { 
     execute(); 
    } 

    @Override 
    public Void doInBackground() { 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException _0) { 
      _0.printStackTrace(); 
     } 
     for (int i = 0; i < 200; i++) { 
      textArea.append("Text"+i+"\n"); 
     } 
     int endPosition_ = textArea.getDocument().getLength(); 
     Rectangle bottom_; 
     try { 
      bottom_ = textArea.modelToView(endPosition_); 
      textArea.scrollRectToVisible(bottom_); 
     } catch (BadLocationException _0) { 
      _0.printStackTrace(); 
     } 
     return null; 
    } 

    /**The equivalent in the class Thread*/ 
    public boolean isAlive() { 
     return !isDone() || !isCancelled(); 
    } 
} 

編輯3:這是一個自定義類從「搖擺」繼承組件:

我的自定義方法是「線程安全的」還是不是?

MyTextArea:

package swingex; 

import javax.swing.JTextArea; 

public class MyTextArea extends JTextArea { 

    private String aField = ""; 

    public String getaField() { 
     return aField; 
    } 

    public void setaField(String _aField) { 
     aField = _aField; 
    } 
} 

現在,我使用SwingUtilities類的方法 「的invokeLater」 從SwingWorker的

+1

爲什麼不使用Swing'Timer'? –

+0

@Catalina島:我想通過使用類Thread的「睡眠」方法來模擬長時間的治療。 – cardman

+1

你可以使用'SwingWorker'或'invokeLater()'。 –

回答

1

的 「doInBackground」 的方法,我認爲你應該做的Swing的EDT行動。所以睡後的一切應該用invokeLater來調用。

這不是併發訪問的問題。我們不應該在其他線程中修改UI。

你可以做的是:

  1. 沒有這個動作創建自己的線程在Runnable
  2. 包裹行動和invokeLater調用它。然後在EDT確保正確的訂單。

長期以來的行動,看看swingworker

爲什麼會有問題? 至少有2個線程:

  1. Swing EDT:您創建所有組件的位置,Swing修改其UI。
  2. 線程在後臺:您在哪裏做了長時間的處理,並且嘗試追加文本。在這裏您可以訪問EDT線程中的對象。
+0

我在「click」事件開始時使用了類Thread的方法isAlive,因此從我的類「AddText」繼承的兩個線程不能同時訪問JTextArea的「append」方法。 – cardman

+0

@cardman:排除你自己對'append'的調用不會阻止用戶輸入到textarea中,即使它是隻讀的,Swing在您的後臺操作對它進行操作時仍可能會嘗試繪製它。這簡直就是壞的。如果您只是將其複製到「SwingWorker」中,則您的代碼無效。你應該按照預期使用它,這在[它的文檔](http://docs.oracle.com/javase/7/docs/api/?javax/swing/SwingWorker.html)中有詳細解釋。 – Holger

+0

@cardman更新了我的答案。無論如何,請先閱讀Swing文檔,然後按照建議進行操作。 –