2016-11-22 6 views
1

スイングメソッドを一度に1つのスレッドで呼び出す方法についていくつかの情報が必要です。コードは1つのスレッドだけで呼び出されるので、私のJAVAコードは安全ですか?

EDIT: 私は、Java 7

を使用する私は、次のトピックを見ました:

Thread Safety of JTextArea.append

私はミニスイングアプリケーションを開発し。

これはスレッドセーフなクラスである私のメインクラスです。 スレッドセーフなクラスにするために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:このクラスはActionListenerを実装して

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(); 
     } 
    } 
} 

、それはボタンをクリックするために使用されています。

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(); 
    } 

} 

は、事前にありがとうございます。

EDIT 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(); 
    } 
} 

EDIT 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; 
    } 
} 

は、私はあなたがSwingのEDTでアクションをやるべきだと思うSwingWorkerの

+1

なぜスイングタイマーを使用しないのですか? –

+0

@Catalina Island:私はクラスThreadのメソッド "sleep"を使って長い治療法をシミュレートしたいと思っていました。 – cardman

+1

'SwingWorker'または' invokeLater() 'を使うことができます。 –

答えて

1

の "doInBackground" メソッドからSwingUtilitiesの方法 "invokeLater" を使用します。だから、睡眠後のすべてはinvokeLaterで呼ぶべきです。

これは同時アクセスの問題ではありません。私たちは他のスレッドでUIを変更することは想定されていません。あなたは何ができるか

は次のとおりです。

  1. は、このアクションのためにRunnable
  2. ラップアクションを独自のスレッドを作成し、invokeLaterでそれを呼び出すことはありませ。その後、EDTで正しい順序が保証されます。

長時間の対応については、swingworkerをご覧ください。

なぜ問題があるのですか? 少なくとも2つのスレッドがあります。

  1. Swing EDT:すべてのコンポーネントを作成し、そのUIを変更します。
  2. バックグラウンドのスレッド:長い治療をしているところで、テキストを追加しようとします。ここでは、EDTスレッドのオブジェクトにアクセスします。
+0

"click"イベントの開始時にクラスThreadのisAliveメソッドを使用したので、クラス "AddText"から継承した2つのスレッドは同時にJTextAreaの "append"メソッドにアクセスできません。 – cardman

+0

@cardman:あなた自身の 'append'呼び出しを除外しても、ユーザーがテキストエリアに入力するのを妨げることはありません。また、読み込み専用であっても、あなたのバックグラウンドアクションがそれを操作するときに、それは単に壊れています。 'SwingWorker'にコピーすれば、コードは有効になりません。これは、[そのドキュメント](http://docs.oracle.com/javase/7/docs/api/?javax/swing/SwingWorker.html)で詳しく説明されています。 – Holger

+0

@cardmanが私の答えを更新しました。とにかく、最初にSwingドキュメントを読んで、それが推奨するようにします。 –

関連する問題