我在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();
}
}
没有必要使用完整的解决方案(虽然它会很好)。我更喜欢关于纠正代码的地方的一些指示。
答案 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);
}
}
这也意味着所有写入请求都排队,您不必担心写入部分的线程安全问题。