У меня есть вариант использования со многими потоками писателей и одним потоком чтения. Записываемые данные - это счетчик событий, который считывается потоком отображения.
Счетчик только увеличивается, а дисплей предназначен для людей, поэтому точное значение момента времени не имеет решающего значения. Для этой цели я считаю решение правильным, если:
- Ценность, которую видит читающий поток, никогда не уменьшается.
- Показания в конечном итоге стабильны. По прошествии определенного времени без записи все операции чтения вернут точное значение.
Предполагая, что писатели правильно синхронизированы друг с другом, необходимо ли синхронизировать поток чтения с писателями, чтобы гарантировать правильность, как определено выше?
Упрощенный пример. Было бы это правильно, как определено выше?
public class Eventual {
private static class Counter {
private int count = 0;
private Lock writeLock = new ReentrantLock();
// Unsynchronized reads
public int getCount() {
return count;
}
// Synchronized writes
public void increment() {
writeLock.lock();
try {
count++;
} finally {
writeLock.unlock();
}
}
}
public static void main(String[] args) {
List<Thread> contentiousThreads = new ArrayList<>();
final Counter sharedCounter = new Counter();
// 5 synchronized writer threads
for(int i = 0; i < 5; ++i) {
contentiousThreads.add(new Thread(new Runnable(){
@Override
public void run() {
for(int i = 0; i < 20_000; ++i) {
sharedCounter.increment();
safeSleep(1);
}
}
}));
}
// 1 unsynchronized reader thread
contentiousThreads.add(new Thread(new Runnable(){
@Override
public void run() {
for(int i = 0; i < 30; ++i) {
// This value should:
// +Never decrease
// +Reach 100,000 if we are eventually consistent.
System.out.println("Count: " + sharedCounter.getCount());
safeSleep(1000);
}
}
}));
contentiousThreads.stream().forEach(t -> t.start());
// Just cleaning up...
// For the question, assume readers/writers run indefinitely
try {
for(Thread t : contentiousThreads) {
t.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void safeSleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
//Don't care about error handling for now.
}
}
}