Let's say I have two threads running like this:
- Thread A which performs computation while updating pixels of a shared image
- Thread B periodically reads the image and copies it to the screen
Thread A performs work quickly, say 1 million updates per second, so I suspect it would be a bad idea to lock and unlock on a lock/mutex/monitor that often. But if there is no lock and no way of establishing a happens-before relation from thread A to thread B, then by the Java memory model (JMM spec) thread B is not guaranteed at all to see any of A's updates to the image.
So I was thinking that the minimum solution is for threads A and B to both synchronize periodically on the same shared lock, but not actually perform any work while inside the synchronized block - this is what makes the pattern non-standard and dubious. To illustrate in half-real half-pseudo code:
class ComputationCanvas extends java.awt.Canvas {
private Object lock = new Object();
private int[] pixels = new int[1000000];
public ComputationCanvas() {
new Thread(this::runThreadA).start();
new Thread(this::runThreadB).start();
}
private void runThreadA() {
while (true) {
for (1000 steps) {
update pixels directly
without synchornization
}
synchronized(lock) {} // Blank
}
}
private void runThreadB() {
while (true) {
Thread.sleep(100);
synchronized(lock) {} // Blank
this.repaint();
}
}
@Override
public void paint(Graphics g) {
g.drawImage(pixels, 0, 0);
}
}
Does adding empty synchronization blocks in this way correctly achieve the effect of transferring data from thread A to thread B? Or is there some other solution I failed to imagine?
volatile
? – Catonvolatile
will cause the cache to become invalidated on every write operation leading to much slower updates in thread a. – Greaserpixels
array while it's been updated byA
– Vilmajava.util.concurrent.atomic.AtomicIntegerArray.lazySet()
– CommissionaireGraphics
doesn’t have adrawImage
method that takes anint[]
array. So a fundamental step is missing in this example. Further, there are three threads involved and third one, the event dispatch thread being the one actually reading the array (if there was adrawImage
method acceptingint[]
) is never usingsynchronized
. Sincerepaint
does nothing but posting some kind of event to the queue (but with some gotchas), you could get rid of the thread B and thesynchronized
and simply post a custom event that solves all issues. – Delacruzsynchronized
block is already outside the pure computation focus. Why should any other approach that also boils down to a single line of code be worse than that? – Delacruz