7

Скажем, у меня есть две темы, работающие, как это:Работает ли этот нестандартный шаблон синхронизации Java?

  • Пронизывайте, который выполняет вычисления при обновлении пикселей общего изображения
  • Thread B периодически считывает изображение и копирует его на экран

Thread A быстро выполняет работу, скажем, 1 миллион обновлений в секунду, поэтому я подозреваю, что было бы неплохо заблокировать и разблокировать блокировку/мьютекс/монитор, что часто. Но если нет блокировки и нет способа установить связь «из-за» из потока A в поток B, то по модели памяти Java (спецификация JMM) нить B не гарантируется вообще, чтобы увидеть какие-либо обновления A для изображения.

Таким образом, я думал, что минимальное решение для потоков A и B для одновременной синхронизации одной и той же общей блокировки, но фактически не выполняет какую-либо работу внутри синхронизированного блока - это то, что делает шаблон нестандартным и сомнительны. В качестве иллюстрации в половину реального кода наполовину псевдо:

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

ли добавлять пустые блоки синхронизации, таким образом, правильно добиться эффекта переноса данных из потоков А в поток B? Или есть другое решение, которое я не мог себе представить?

+1

Почему атомный булев не должен делать трюк? Синхронизация ни на чем не оставляет работу из синхронизации – efekctive

+3

Почему бы не использовать 'volatile'? – shmosel

+0

Возможно: http://stackoverflow.com/questions/17108541/happens-before-relationships-with-volatile-fields-and-synchronized-blocks-in-jav – flakes

ответ

1

Да, это работает. Но это работает ужасно.

Случается до того, как работает только когда освобождение писателя происходит до приобретения читателя. В вашей реализации предполагается, что все, что вы пишете, завершится до последующего чтения/обновления с ThreadB. Из-за того, что ваши данные будут красными все время синхронизированы, это вызовет проблемы с производительностью, хотя, насколько я не могу сказать точно. Несомненно, вы сделали вашу синхронизацию более зернистой, вы уже ее протестировали?

Лучшее решение может использовать очередь одиночной/передачи SPSC (одиночный производитель/одиночный потребитель) для хранения текущего моментального снимка потока записи и его использования при каждом обновлении.

int[] data = ... 
Queue<int[]> queue = new ... 

// Thread A 
while (true) { 
    for (1000 iterations or so) { 
     ... 
    } 
    queue.add(data); 
} 

// Thread B 
while (true) { 
    int[] snapshot = queue.take(); 
    this.repaint(); 
} 

Преимущество этого в том, что вам не нужно busywait, вы можете просто ждать очереди, чтобы блокировать или до следующей записи. Вы можете пропустить записи, которые у вас нет времени для обновления. Вам не нужно зависеть от произвольного планировщика потоков для планирования потоков данных для вас.

Помните, что потокобезопасные структуры данных отлично подходят для передачи данных между потоками.

Редактировать: oops, забыли сказать, что в зависимости от того, как ваши обновления идут, вы можете использовать копию массива, чтобы ваши данные не искажались из случайных записей, которые не кэшируются.

+0

'repaint' не принимает никаких параметров –

+0

@DavidConrad, вы правы, думал о методе краски ниже. – xTrollxDudex

+0

Можно также передавать данные пикселя через AtomicReference, но очередь превосходит по причинам, которые вы указали, - не ожидание ожидания или проблемы с расписанием. Я использовал этот образец много раз с большим успехом. – user949300

Смежные вопросы