问题如下,我有一个 LocalDateTime 数组
LocalDateTime[] alarmzeiten = new LocalDateTime[100];
当程序启动时,数组会在程序启动时从 .dat 填充,或者在程序中随时通过用户输入填充,因此数组括号要么为空,要么保存 LocalDateTime。
除了主函数之外,我还有这个线程:
public void run() {
while(true){
for(int i = 0; i < alarmzeiten.length; i++){
System.out.println(alarmzeiten[i]);
}
线程应该不断地向我显示 LocalDateTime 数组中是否发生变化。如果我将更改保存在 .dat 中并再次启动程序,那么查看所做的更改是没有问题的。不过,这个线程的问题是,如果我在程序中的某个时候更改数组,它仍然会像程序开头一样打印数组。当用户在任何给定点对数组进行更改并且我在主函数中使用按钮显示数组时,它会显示数组已更改,就像它应该的那样。
数组发生变化的部分:
JButton btnsetAlarm = new JButton("Alarm stellen");
btnsetAlarm.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try{
DateChooserToPieces datumsverarbeiter = new DateChooserToPieces(String.valueOf(dateChooser.getDate()));
alarmzeiten[listAufgaben.getSelectedIndex()] = LocalDateTime.of(datumsverarbeiter.getYear(), datumsverarbeiter.getMonth(),
datumsverarbeiter.getDay(), Integer.parseInt(String.valueOf(cbStunde.getSelectedItem())), Integer.parseInt(String.valueOf(cbMinute.getSelectedItem())));
}
catch(ArrayIndexOutOfBoundsException ex){
JOptionPane.showMessageDialog(null, "Bitte wählen Sie eine Aufgabe aus!");
}
}
我把同样的问题放在更小的代码中,这样我就可以将其全部发布在这里以获得完整的信息!主要部分如下:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class VisualThreadTest extends JFrame {
private JPanel contentPane;
private JTextField textField;
String threadTestString = "Test";
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
VisualThreadTest frame = new VisualThreadTest();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public VisualThreadTest() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
Thread a = new Thread(new Thread1(threadTestString));
a.start();
JTextField tf = new JTextField();
tf.setBounds(10, 11, 86, 20);
contentPane.add(tf);
tf.setColumns(10);
JButton btnNewButton = new JButton("New button"); //here it should change threadTestString to something I put in the textfield and the Thread
btnNewButton.addActionListener(new ActionListener() { // should print the change
public void actionPerformed(ActionEvent arg0) {
threadTestString=tf.getText();
System.out.println(threadTestString);
}
});
btnNewButton.setBounds(106, 10, 89, 23);
contentPane.add(btnNewButton);
}
}
这是 Thread1 类:
public class Thread1 implements Runnable{
String threadString;
Thread1(String d){
threadString = d;
}
@Override public void run(){
while(true){
System.out.println(threadString + " Thread1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
最佳答案
LocalDateTime[] alarmzeiten = new LocalDateTime[100];
是一个数组,并且数组的元素在共享它的线程之间不一致且可靠地更新。
根据你的说法,用户操作是在读取数组的另一个线程中执行的:
public void run() {
while(true){
for(int i = 0; i < alarmzeiten.length; i++){
System.out.println(alarmzeiten[i]);
}
}
最后,您的问题是打印元素的线程具有未更新的数组对象版本。
如何解决?
使用 volatile 修饰符不会有任何帮助,因为带有 volatile 修饰符的数组或列表不会为其元素提供 volatile 行为。
更可靠的解决方案是在使用数组时使用显式同步。
当您访问数组时,您可以在数组上使用同步语句。
通过这种方式,每个线程都将拥有对数组状态的独占访问权,并且将创建一个发生之前的关系,该关系将提供对象在其最后版本中的可见性。
打印元素的线程可以做:
public void run() {
while(true){
synchronized(alarmzeiten){
for(int i = 0; i < alarmzeiten.length; i++){
System.out.println(alarmzeiten[i]);
}
}
}
并且在线程中用户可以做到这一点:
synchronized(alarmzeiten){
alarmzeiten[listAufgaben.getSelectedIndex()] = LocalDateTime.of(datumsverarbeiter.getYear(), datumsverarbeiter.getMonth(),
}
关于java - 同一数组的两个不同输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44482632/