3

Hi I have a paint method that is drawing an image and I have another method that is constantly modifying the image to be drawn however I experience concurrency exceptions now and again. What is the most efficient way to resolve this please? I know I could use synchronized blocks on the buffered image but then it throws up warnings on synchronizing a none 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);
    }
}
7
  • You could alternate between two different buffers. One for rendering and one for editing. Commented Apr 29, 2015 at 23:56
  • Sorry could you give an example of how to achieve this using buffers Commented Apr 29, 2015 at 23:58
  • There's nothing inherently wrong with synchronizing on a non-final variable. You might have your warning level set unnecessarily high. Commented Apr 30, 2015 at 0:28
  • @immibis: There's plenty wrong with it if it's synchronized (img), which is what "use synchronized blocks on the buffered image" sounds like. Commented Apr 30, 2015 at 0:35
  • 1
    @user2357112 Sure, there are potential bugs that involve synchronized and non-final variables, but IMO the signal-to-noise ratio of that warning is way too low. (Why not a "calling method on non-final variable" warning?) Commented Apr 30, 2015 at 0:36

3 Answers 3

1

you could sync on 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);
       }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

You have a race condition because the value of img can changed in another thread between the if conditional and the use of img in drawImage

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

You can assign img to a local variable, then use the local variable in-place of img in the above code. The local variable will remain constant even if img is changed to a different object in another thread

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

In addition to this, img should be declared as volatile so its value is not cached thread-locally; changes in one thread will be seen by others.

private volatile BufferedImage img;

Bear in mind that declaring a variable as volatile will cause synchronization to occur whenever that variable is accessed; so synchronization is still happening. However, synchronization occurs on the img reference itself, not the BufferedImage object to which it refers, so there are no issues here if img is null.

2 Comments

Without synchronization, there's no guarantee the thread reading img will see the other thread's writes.
@user2357112 Good point! img would need to be declared as volatile. I will update my answer.
0

There's a thread-safety issue because the contents of the BufferedImage can be changed while the paintComponent method is running. Synchronization and volatile in the ui class alone won't fix this.

If you want to add synchronization, then you'll need to make sure any modification of the image is synchronized as well. This needs to be synchronized on some object that's shared between each class involved.

You can avoid some synchronization by making sure to set img to a copy of the BufferedImage or a different instance each time. It should still be volatile though, and check pathfinderelite's answer if you want to safely set img back to null.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.