Java concurrent exception

Hi I have a paint method that draws an image and I have another method that constantly changes the image to be drawn, however I am experiencing concurrency exceptions over and over again. What is the most efficient way to solve this problem? I know that I could use synchronized blocks on a buffered image, but then it generates warnings about synchronized final variable.

private BufferedImage img;

public void modImage(BufferedImage image) { 
     img = image;
}

public void paintComponent(Graphics g) {
    if (img != null) {
        g.drawImage(img, 0, 0, this);
    }
}

      

+3


source to share


3 answers


You have a race condition because the value img

can be changed in a different thread between the conditional expression if

and use img

indrawImage

if (img != null) {                     // <-- img can be non-null here
    g.drawImage(img, 0, 0, this);      // <-- img can now be null
}

      

You can assign to a img

local variable and then use the local variable instead img

in the above code. The local variable will remain constant even if img

changed to another object on a different thread

final BufferedImage localImg = img;      // <-- localImg won't change locally
if (localImg != null) {
    g.drawImage(localImg, 0, 0, this);
}

      



In addition to this, it img

must be declared as volatile

, so its value is not thread-locally cached; changes in one thread will be visible to others.

private volatile BufferedImage img;

      

Be aware that declaring a variable as volatile

will cause synchronization to occur every time the variable is accessed; so sync is still happening. However, synchronization happens in the link itself img

, not in the object BufferedImage

to which it refers, so there is no problem here if img

any null

.

+1


source


you can sync the instance,



private BufferedImage img;

public void modImage(BufferedImage image) { 
     synchronized(this){
         img = image;
     }
}

public void paintComponent(Graphics g) {
    synchronized(this){
    if (img != null) {
        g.drawImage(img, 0, 0, this);
       }
    }
}

      

+1


source


There is a thread safety issue because the content BufferedImage

can be changed when the method is run paintComponent

. Synchronization and volatility in the ui class alone won't fix this.

If you want to add sync, you need to make sure that any image modification is also synced. This needs to be synchronized on some object that is used for each class.

You can avoid some synchronization by putting img

on an instance BufferedImage

or a different instance each time. It should be mutable anyway, and check pathfinderelite's answer if you want to securely install img

on null

.

0


source







All Articles