【问题标题】:Is my JAVA code thread safe, as the code is called by only one thread?我的 JAVA 代码线程安全吗,因为代码只有一个线程调用?
【发布时间】:2016-11-22 12:46:33
【问题描述】:

我想了解一些关于一个线程一次调用swing方法的信息。

编辑: 我使用 Java 7。

我看到了以下话题:

Thread Safety of JTextArea.append

我开发了一个迷你秋千应用程序。

这是我的主类,它是一个线程安全的类。 我调用 SwingUtilities.invokeLater 方法使其成为线程安全类。

主类:

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 行添加到文本区域。 添加文本:

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,用于点击按钮。

添加文本事件:

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:它是一个继承自“swing”组件的自定义类:

我的自定义方法是否“线程安全”?

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

现在,我使用 SwingWorker 的“doInBackground”方法中的 SwingUtilities 的“invokeLater”方法

【问题讨论】:

  • 为什么不使用 Swing Timer
  • @Catalina Island:我想用Thread类的“sleep”方法来模拟长时间的治疗。
  • 您可以使用SwingWorkerinvokeLater()
  • 不,doInBackground 将在后台线程中调用,这是您进行长时间处理的地方(如睡眠...),因此它不会阻塞 UI。您应该在 done 方法中更新您的 UI。查看 Holger 评论中的文档。
  • @grape_mao:我看到Marek Blotny的回答:What is meant by thread safe code ?,如果只有两个或多个线程调用append方法,那么可能有问题。

标签: java multithreading swing thread-safety


【解决方案1】:

我认为你应该在 Swing 的EDT 中执行操作。所以睡眠后的一切都应该用invokeLater调用。

这不是并发访问的问题。我们不应该在其他线程中修改 UI。

你可以做的是:

  1. 不要为此操作创建自己的线程
  2. 将动作包装在Runnable 中并使用invokeLater 调用它。然后在 EDT 中将保证正确的订单。

对于长时间的操作,请查看swingworker

为什么会出现问题? 至少有 2 个线程:

  1. Swing EDT:您可以在其中创建所有组件,Swing 会修改其 UI。
  2. 后台线程:您在此处进行长时间处理并尝试附加文本。您可以在此处访问 EDT 线程中的对象。

【讨论】:

  • 我在"click"事件开始时使用了Thread类的isAlive方法,所以从我的类"AddText"继承的两个线程不能同时访问JTextArea的"append"方法。跨度>
  • @cardman: 排除您自己对append 的调用不会阻止用户在文本区域中输入,即使它是只读的,Swing 仍可能在您的后台操作会操纵它。那简直是坏掉了。如果您只是将其复制到 SwingWorker 中,您的代码将无效。您应该按预期使用它,its documentation 中有详细说明。
  • @cardman 更新了我的答案。无论如何,请先阅读 Swing 文档并按照它的建议做事。
猜你喜欢
  • 2014-10-08
  • 2015-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
相关资源
最近更新 更多