ここでは、リストにアクセスできる2つのスレッドを持つクラスがあります。 1つのスレッドは定期的に更新されたコピーでリストを置き換え、もう1つのスレッドはリストの内容を画面にペイントします。1つのスレッドでのみ変更されたリストへのアクセスを同期する必要はありますか?
public class ThreadSafePainter {
private List<String> dataList = new ArrayList<>();
/*
* starts a thread to periodically update the dataList
*/
public ThreadSafePainter() {
Thread thread = new Thread(() -> {
while (true) {
// replace out-dated list with the updated data
this.dataList = getUpdatedData();
// wait a few seconds before updating again
Thread.sleep(5000);
}
});
thread.start();
}
/*
* called 10 times/second from a separate paint thread
* Q: Does access to dataList need to be synchronized?
*/
public void onPaint(Graphics2D g) {
Point p = new Point(20, 20);
// iterate through the data and display it on-screen
for (String data : dataList) {
g.drawString(data, p.x, p.y);
p.translate(0, 20);
}
}
/*
* time consuming data retrieval
*/
private List<String> getUpdatedData() {
List<String> data = new ArrayList<>();
// retrieve external data and populate list
return data;
}
}
私の質問は、データリストへのアクセスを同期する必要がありますか?それをどうやってやりますか?
public ThreadSafePainter() {
...
synchronized (this) {
this.dataList = getUpdatedData();
}
...
}
public void onPaint(Graphics2D g) {
...
synchronized (this) {
for (String data : dataList)
...
}
}
すべての繰り返しで画面全体を再描画しますか? – StackFlowed
'getUpdatedData()'は毎回新しいリストを作成するので、安全なパブリケーションのみが必要です。この場合、 'dataList'フィールドを' volatile'と宣言するだけで十分です。リストの参照が格納された後にリストの参照が格納され、再度変更されない場合(次の更新が新しいリストを作成するとき)、読み込み者が処理ごとに参照を読み込むことが重要です( 'for(...:dataList) ')。 1つの 'paint'の間にリストに複数回アクセスする必要がある場合は、それをローカル変数に格納する必要があります。 – Holger
2つ以上のスレッドが**変更可能な**状態を共有するたびに、**同時実行性を処理するための何らかのメカニズムが必要です**。低レベルの同期であれ、より高いレベルの並行処理クラスであれ、 'Atomic *'クラスまたは 'volatile'フィールドは実際の状況に依存しますが、何かを常に配置しなければなりません。 – biziclop