java - 我的 JAVA 代码线程安全吗,因为该代码仅由一个线程调用?

标签 java multithreading swing thread-safety

我想要一些有关一次通过一个线程调用 swing 方法的信息。

编辑: 我使用 Java 7。

我看到了以下主题:

Thread Safety of JTextArea.append

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

这是我的主类,它是一个线程安全类。 我调用 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的类。 我在内容 Pane 中放置了一个文本区域和一个按钮。

主窗口:

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

单击按钮会使线程 hibernate 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”组件的自定义类:

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

我的文本区域:

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 的 EDT 中执行操作。因此, sleep 后的所有内容都应该使用 invokeLater 调用。

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

你可以做的是:

  1. 不要为此操作创建自己的线程
  2. 将操作包装在 Runnable 中,并使用 invokeLater 调用它。那么在 EDT 中将保证正确的顺序。

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

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

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

关于java - 我的 JAVA 代码线程安全吗,因为该代码仅由一个线程调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40742268/

相关文章:

java - 如何使用新的 OSGi 声明式服务注释?

java - Hibernate PostgreSQL OneToOne 关系首先触发子查询

java - 网络线程和 Swing 线程出现问题

python - Gunicorn 线程没有任何区别

java - 在四核上使用 Executors.newFixedThreadPool 进行 2 次或 4 次 Future 提交没有区别

java - Micronaut,声明式 Http-Client,JSON 序列化包装 HTTP Post 对象

c# - C#: Call a method every 5 minutes from a foreach loop

java - 获取固定大小的 GridLayout

java - 如何将 Swing TreeNode 转换为 Apache Tobago TreePath?

java - JScrollPane:垂直条可见但不活动