2015-04-29 6 views
3

Привет У меня есть метод рисования, который рисует изображение, и у меня есть другой метод, который постоянно изменяет изображение, которое нужно нарисовать, но я снова и снова испытываю исключения параллелизма. Каков наиболее эффективный способ решить эту проблему? Я знаю, что я мог бы использовать синхронизированные блоки на буферизованном изображении, но затем он выдает предупреждения о синхронизации ни одной конечной переменной.Java Concurrent Exception

private BufferedImage img; 

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

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

Вы можете чередовать два разных буфера. Один для рендеринга и один для редактирования. – Harvtronix

+0

Извините, не могли бы вы привести пример того, как этого добиться с помощью буферов. –

+0

В синхронизации с несинтетической переменной ничего не происходит. Возможно, ваш уровень предупреждения слишком высок. – immibis

ответ

1

У вас есть условие гонки, так как значение img может изменить в другом потоке между if условна и использование img в drawImage

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.

+1

Без синхронизации нет гарантии, что поток, читающий 'img', увидит записи другого потока. – user2357112

+0

@ user2357112 Хорошая точка! 'img' нужно будет объявить изменчивым. Я уточню свой ответ. – pathfinderelite

1

можно синхронизировать на экземпляре,

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); 
     } 
    } 
} 
0

Там есть проблема безопасности потоков, так как содержимое BufferedImage может быть изменен во время метод paintComponent работает. Синхронизация и неустойчивость только в классе ui не исправят это.

Если вы хотите добавить синхронизацию, вам необходимо убедиться, что любая модификация изображения также синхронизирована. Это необходимо синхронизировать на каком-либо объекте, который используется для каждого класса.

Вы можете избежать некоторой синхронизации, указав при этом img на экземпляр BufferedImage или на другой экземпляр каждый раз. Он все равно должен быть неустойчивым и проверить ответ pathfinderelite, если вы хотите безопасно установить img на номер null.