问题如下,我有一个LocalDateTime数组
LocalDateTime[] alarmzeiten = new LocalDateTime[100];
当程序启动时,程序在程序启动时从.dat填充,或者在程序中随时通过userinput填充,因此数组括号为null或保持LocalDateTime。
除了主要功能我有这个帖子:
public void run() {
while(true){
for(int i = 0; i < alarmzeiten.length; i++){
System.out.println(alarmzeiten[i]);
}
如果LocalDateTime数组中发生了某些变化,线程应该不断显示。如果我保护.dat中的更改并再次启动程序,则看到所做的更改没有问题。这个线程的问题是,如果我在程序中更改了某个数组,它仍然会像程序开头那样打印数组。当用户在任何给定点对数组进行更改并使用main函数中的按钮显示数组时,它会显示更改的数组,就像它应该的那样。
数组更改的部分:
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);
}
}
这是Class 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();
}
}
}
}
答案 0 :(得分:1)
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
修饰符的List不会向其元素提供volatile
行为。
更可靠的解决方案是在使用数组时使用显式同步 访问阵列时,可以在阵列上使用synchronized语句 通过这种方式,每个线程将拥有对数组状态的独占访问权,并且它将创建一个先发生的关系,它将在上一个版本中提供对象的可见性。
打印元素的线程可以:
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(),
}
答案 1 :(得分:0)
我将以线程安全的方式创建一个使用 monitor 的Java解决方案,以便对alarmzeiten
进行唯一数据访问。我在这里提供了一个代码片段:
public class timePrint implements Runnable {
private LocalDateTime[] alarmzeiten = new LocalDateTime[100];
public LocalDateTime[] getAlarmzeiten() {
synchronized (alarmzeiten) {
return alarmzeiten;
}
}
public void setAlarmzeiten(LocalDateTime[] alarmzeiten) {
synchronized (alarmzeiten) {
this.alarmzeiten = alarmzeiten;
}
}
@Override
public void run() {
while (true) {
synchronized (alarmzeiten) {
for (LocalDateTime localDateTime : alarmzeiten) {
System.out.println(localDateTime);
}
}
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println(e);
}
}
}
}
(修改了代码段,以便在Runnable
中合并共享内存)。
请注意,alarmzeiten
的其他访问点也需要使用synchronized
构造(用于线程安全的共享内存访问)。
需要sleep
来释放共享数据阵列的线程访问权限。
您可以添加一个单独的get方法,并将数组索引作为输入参数。还可以实现类似的设置方法(使用索引)。两种方法都需要使用synchronized
构造。
答案 2 :(得分:0)
多线程环境也需要考虑可见性,即某些同步或compareAndSet,这就像内存同步的非阻塞机制。
您可以使用CopyOnWriteArrayList ob= new CopyOnWriteArrayList();
集合。
这里迭代时不需要锁定,也没有并发修改异常。
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
List<Integer> list = new CopyOnWriteArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
new WriteThread("Writer", list).start();
new ReadThread("Reader", list).start();
}
}
class WriteThread extends Thread {
private List<Integer> list;
public WriteThread(String name, List<Integer> list) {
this.list = list;
super.setName(name);
}
public void run() {
int count = 6;
while (true) {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
list.add(count++);
System.out.println(super.getName() + " done");
}
}
}
class ReadThread extends Thread {
private List<Integer> list;
public ReadThread(String name, List<Integer> list) {
this.list = list;
super.setName(name);
}
public void run() {
while (true) {
String output = "\n" + super.getName() + ":";
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer next = iterator.next();
output += " " + next;
// fake processing time
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.println(output);
}
}
}
或者您可以检查并发包。也可以使用atomicreferencearray。
AtomicReferenceArray<String> array =
new AtomicReferenceArray<String>(source);
array.compareAndSet(5, string1, string2);