您好,我有一个正在绘制图像的paint方法,还有一个不断修改要绘制的图像的方法,但是我经常遇到并发异常。请问解决这个问题最有效的方法是什么?我知道我可以在缓冲的映像上使用同步块,但是它会在同步none final变量时抛出警告。
private BufferedImage img;
public void modImage(BufferedImage image) {
img = image;
}
public void paintComponent(Graphics g) {
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}发布于 2015-04-30 08:23:08
您有一个争用条件,因为在if条件和在drawImage中使用img之间,img的值可以在另一个线程中更改
if (img != null) { // <-- img can be non-null here
g.drawImage(img, 0, 0, this); // <-- img can now be null
}您可以将img赋给一个局部变量,然后在上面的代码中使用局部变量来代替img。即使将img更改为另一个线程中的其他对象,局部变量也将保持不变
final BufferedImage localImg = img; // <-- localImg won't change locally
if (localImg != null) {
g.drawImage(localImg, 0, 0, this);
}除此之外,应该将img声明为volatile,这样它的值就不会被线程本地缓存;一个线程中的更改将被其他线程看到。
private volatile BufferedImage img;请记住,将变量声明为volatile将导致无论何时访问该变量都会发生同步;因此同步仍然会发生。但是,同步发生在img引用本身,而不是它所引用的BufferedImage对象上,因此如果img为null,则不会有任何问题。
发布于 2015-04-30 08:39:33
你可以在实例上同步,
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);
}
}
}发布于 2015-04-30 09:17:51
这存在一个线程安全问题,因为在运行paintComponent方法时可以更改BufferedImage的内容。仅在ui类中使用同步和易失性并不能解决这个问题。
如果要添加同步,则需要确保对映像的任何修改也是同步的。这需要在涉及的每个类之间共享的某个对象上进行同步。
通过确保每次都将img设置为BufferedImage的副本或不同的实例,可以避免某些同步。不过,它应该仍然是易失性的,如果你想安全地将img设置回null,请检查探路者精英的答案。
https://stackoverflow.com/questions/29956641
复制相似问题