使用CachedThreadPool写入JTextArea

时间:2015-05-31 19:27:38

标签: java multithreading swing thread-safety

我在CodeReview中问了这个问题,但它已经关闭了。

对于学校作业,我必须创建54个线程,这些线程同时从Executors.newCachedThreadPool()以线程安全的方式写入JTextArea。每个线程必须将'A'到'Z'写入字段1000次。无论我在哪里放synchronized关键字,我一直遇到使程序线程安全的问题。我有一个可运行的类来完成写作,但我遇到了保持线程安全的问题。我试过的唯一方法就是在循环中放置Thread.sleep(500)循环遍历所有字母,当我增加迭代并且无论如何都在Netbeans中发出警告时这不起作用。

synchronized关键字放在正确的位置使线程安全或我是否必须更改线程本身?我在下面的评论中留下了我以前的一些尝试。

我更改了代码以使其工作一次。它运行一个写入JTextArea的实例,但是我遇到了将其转换为多个同步线程的问题。

AlphabetThread.java

package threadpool;

import javax.swing.JTextArea;

public class AlphabetThread implements Runnable{

    char letter;
    JTextArea toEdit;
    //final int NUMBER_OF_ITERATIONS = 1000;

    public AlphabetThread(char e, JTextArea tf) {
        letter = e;
        toEdit = tf;
    }

    @Override
    public void run() {
        //for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {

            toEdit.setText(toEdit.getText() + letter);

    }

//    public synchronized void createThread() {
//        for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
//
//            toEdit.setText(toEdit.getText() + letter);
//        }
//    }
}

ThreadPool.java

package threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {

//    static char letter;
//
//    Thread alphabetThread = new Thread(() -> {
//        char e = letter;
//        mainWindow.textBox.setText(mainWindow.textBox.getText() + e);
//    });
//    public static synchronized AlphabetThread createThread(char e, JTextArea tf) throws InterruptedException {
//        AlphabetThread runMe = new AlphabetThread(e, tf);
//        return runMe;
//    }
    public static void main(String[] args) {
        TextWindow mainWindow = new TextWindow();
        ExecutorService pool = Executors.newCachedThreadPool();

        for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {

            AlphabetThread alphabetThread = new AlphabetThread(alphabet, mainWindow.textBox);
            alphabetThread.run();

        }
        pool.shutdown();
    }
}

TextWindow.java

package threadpool;

import java.awt.Dimension;
import java.awt.HeadlessException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class TextWindow extends JFrame {

    public JPanel mainPanel = new JPanel();
    public JTextArea textBox = new JTextArea();

    public TextWindow() throws HeadlessException {

        add(mainPanel);
        textBox.setPreferredSize(new Dimension(450,450));
        textBox.setVisible(true);
        mainPanel.add(textBox);
        setVisible(true);
        setSize(500, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        pack();
    }

}

没有必要使用完整的解决方案(虽然它会很好)。我更喜欢关于纠正代码的地方的一些指示。

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题。首先,一般规则是您需要使用所有线程的相同监视器对象进行同步。您的尝试似乎也在同步创建线程,而不是在写入文本区域时。 如果swing是线程安全的,您可以使用文本区域作为监视器对象,例如:

synchronized (toEdit) {
    toEdit.setText(toEdit.getText() + letter);
}

这足以同步写入。但是, swing不是线程安全的。这是第二个问题。必须仅在事件派发线程中修改JComponents。这是使用invokeLater()或(很少)invokeAndWait()

完成的
SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        toEdit.setText(toEdit.getText() + letter);
    }
}

这也意味着所有写入请求都排队,您不必担心写入部分的线程安全问题。