当它使用两个计数器和一个时钟时,它们都在不同的线程中工作时,是否存在任何同步问题?



我需要两个计数器像国际象棋时钟一样工作。第一个开始,第二个停止。当第二个开始时,第一个停止。与这两个计数器并行,我需要另一个永不停止的时钟。

我正在努力去做。我创建了两个计数器,它工作得很好,但是当我创建一个新的线程(总共3个线程),这将运行时钟,它会导致一些问题(同时增加两个计数器)。

这些问题是否与同步问题有关?为什么它正确地运行2线程,而不是三个?

//////////////////////////////// HOW THE OBJECTS ARE CREATED /////////////////////////
private Relogio relogioBranco, relogioPreto;
private RelogioGeral relogioGeral;
relogioBranco = new Relogio(relogioBrancoLabel);
relogioPreto = new Relogio(relogioPretoLabel);
relogioGeral= new RelogioGeral(relogioPretoLabel,menu);
new Thread(relogioBranco).start();
new Thread(relogioPreto).start();
new Thread(relogioGeral).start();
relogioBranco.rodarRelogio(false);
relogioPreto.rodarRelogio(false);
relogioGeral.rodarRelogio(true);
////////////////////////////////////// COUNTERS //////////////////////////////
// The clock will be used to autosave my game every 1 minute
package Janela;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.JLabel;
public class Relogio implements Runnable, Serializable {
    private volatile AtomicInteger segundo, minuto, hora;
    private JLabel relogioLabel;
    private boolean relogioRodando;
    public Relogio(JLabel relogio) {
        segundo = new AtomicInteger();
        minuto =  new AtomicInteger();
        hora =  new AtomicInteger();
        minuto.set(0);
        hora.set(0);
        segundo.set(0);
        minuto.set(0);
        this.relogioLabel = relogio;
    }
    public void rodarRelogio(boolean rodar) {
        relogioRodando = rodar;
    }
    @Override
    public void run() {
        try {
            while (true) {
                Thread.sleep(1000);
                if (relogioRodando) {
                    segundo.incrementAndGet();
                    if (segundo.intValue() == 60) {
                        segundo.set(0);
                        minuto.incrementAndGet();
                        if (minuto.intValue() == 60) {
                            minuto.set(0);
                            hora.incrementAndGet();
                            if (hora.intValue() == 24) {
                                segundo.set(0);
                                minuto.set(0);
                                hora.set(0);
                            }
                        }
                    }
                    String tempo = String.format("%02d:%02d:%02d", hora.intValue(), minuto.intValue(), segundo.intValue());
                    relogioLabel.setText(tempo);
                }
            }
        } catch (InterruptedException ie) {
            System.out.println("EXCEÇÃO INTERRUPTED EXCEPTION");
        }
    }
}

///////////////////////////////////////////// CLOCK ///////////////////////////////////
package Janela;
import MesaTabuleiro.ArrayPecas;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class RelogioGeral implements Runnable, Serializable {
private volatile AtomicInteger segundo, minuto, hora;
private final JLabel relogioLabel;
private boolean relogioRodando;
public RelogioGeral(JLabel relogio, Menu menu) {
    segundo = new AtomicInteger();
    minuto = new AtomicInteger();
    hora = new AtomicInteger();
    segundo.set(0);
    minuto.set(0);
    hora.set(0);
    this.relogioLabel = relogio;
}
public void rodarRelogio(boolean rodar) {
    relogioRodando = rodar;
}
@Override
public void run() {
    try {
        while (true) {
            Thread.sleep(1000);
            if (relogioRodando) {
                segundo.incrementAndGet();
                if (segundo.intValue() == 60) {
                    segundo.set(0);
                    minuto.incrementAndGet();
                    if (minuto.intValue() == 60) {
                        minuto.set(0);
                        hora.incrementAndGet();
                        if (hora.intValue() == 24) {
                            segundo.set(0);
                            minuto.set(0);
                            hora.set(0);
                        }
                    }
                }
                String tempo = String.format("%02d:%02d:%02d", hora.intValue(), minuto.intValue(), segundo.intValue());
                relogioLabel.setText(tempo);
                if (minuto.intValue() %1 == 1) {
                    saveGame();
                }
            }
        }
    } catch (InterruptedException ie) {
        System.out.println("EXCEÇÃO INTERRUPTED EXCEPTION");
    }
}
public void saveGame() {
    JOptionPane.showMessageDialog(null, " 1 Minuto de Partida. Salvando Jogo.");
    FileOutputStream output;
    ObjectOutputStream oos = null;
    try {
        output = new FileOutputStream("jogo.ser");
        oos = new ObjectOutputStream(output);
        oos.writeObject(ArrayPecas.getInst().getPecasPretas());
        oos.writeObject(ArrayPecas.getInst().getPecasBrancas());
        oos.writeObject(ArrayPecas.getInst().getxPerdePr());
        oos.writeObject(ArrayPecas.getInst().getyPerdePr());
        oos.writeObject(ArrayPecas.getInst().getxPerdeBr());
        oos.writeObject(ArrayPecas.getInst().getyPerdeBr());
        oos.writeObject(TelaMenuJogo.getTela().getXequeVsbl());
        oos.writeObject(TelaMenuJogo.getTela().getXequeMateVsbl());
        oos.writeObject(TelaMenuJogo.getTela().getHistoricoTxt());
        oos.writeObject(TelaMenuJogo.getTela().getJaDesenhou());
        oos.writeObject(TelaMenuJogo.getTela().getLinha());
        oos.writeObject(TelaMenuJogo.getTela().getColuna());
        oos.writeObject(TelaMenuJogo.getTela().getLinPecaSel());
        oos.writeObject(TelaMenuJogo.getTela().getColPecaSel());
        oos.writeObject(TelaMenuJogo.getTela().getQtdJogadas());
        oos.writeObject(TelaMenuJogo.getTela().getJogador());
    } catch (FileNotFoundException ex) {
        JOptionPane.showMessageDialog(null, "Arquivo nao encontrado");
    } catch (IOException ex) {
        ex.printStackTrace();
        JOptionPane.showMessageDialog(null, "Erro ao tentar gravar no arquivo de saida");
    } finally {
        if (oos != null) {
            try {
                oos.close();
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(null, "Erro ao fechar arquivo de saida");
            }
        }
    }
}

}

我认为你传递给主时钟的标签和传递给其他时钟的标签是一样的:

relogioBranco = new Relogio(relogioBrancoLabel);
relogioPreto = new Relogio(relogioPretoLabel);
relogioGeral= new RelogioGeral(relogioPretoLabel,menu);

不应该有自己的标签吗?

我认为这个问题与并发无关。你只会得到并发问题,如果两个线程正在工作一个资源(例如线程a和线程b都读取相同的字段)。这里的情况并非如此。每个线程都有自己的变量/对象

最新更新