来自同一阵列的两个不同输出

时间:2017-06-11 10:12:23

标签: java arrays multithreading

问题如下,我有一个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();
            }
        }
    }

}

3 个答案:

答案 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);