Потоки Java: синхронизированные блоки

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

public class ThreadStarter {
    public static void main(String[] args) {

        Queue queueObject = new Queue();

        ThreadA thread1 = new ThreadA(queueObject);
        ThreadA thread2 = new ThreadA(queueObject);

        ThreadB thread3 = new ThreadB(queueObject);
        ThreadB thread4 = new ThreadB(queueObject);

        thread1.start();
        thread2.start();

    }
}

public class Queue {

    Object[] the theQueue;

    public Queue(int size){
        theQueue = new Object[size];
    }

    public submitObject(Object o){
        /* add Object to the queue */
    }

    public deleteObject(int objectId){
        /*delete Object from the queue */
    }
}

public class ThreadA extends Thread {

    private Queue queue;

    public ThreadA(Queue queue){
        this.queue = queue;
    }

    public void run() {
        while(!isInterrupted()){
            synchronized(queue) {
                Object o = new Object
                queue.submitObject(o);
                 /* do some other stuff */
        }

        try {
            sleep((int)(Math.random()*1000));
        } catch (interruptedException) {
            Thread.currentThread().interrupt;
        }

            synchronized(queue) {
                 /* do some other stuff on the queue */
            }
        }
    }
}

public class ThreadB extends Thread {

    private Queue queue;

    public ThreadB(Queue queue){
        this.queue = queue;
    }

    public void run() {
        while(!isInterrupted()){
            synchronized(queue) {
                queue.deleteObject(o);
                /* do some other stuff */
        }

        try {
            sleep(1000);
        } catch (interruptedException) {
            Thread.currentThread().interrupt;
        }
    }
}
}

Мой вопрос: достаточно ли синхронизировать весь объект очереди в ThreadA, чтобы передать объект в класс очереди, чтобы быть в безопасности? Я сделал то же самое в ThreadB, чтобы удалить объект из очереди. Или мне нужно синхронизировать метод submitObject() и deleteObject() в классе Queue?

В моем понимании, если я заблокирую весь класс Queue в потоках, как показано выше, я должен быть в безопасности - правильно?

greetZ и заранее спасибо.

3 ответа

Решение

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

Кроме того, если вы хотите иметь какой-то механизм блокировки, такой как:

"если поток хочет удалить объект, он должен ждать, если в очереди нет такого объекта".

тогда вам нужно сделать больше, чем просто синхронизировать таким образом: оба метода должны быть синхронизированы, но поток, входящий в deleteObject, должен быть остановлен с помощью this.wait в очереди, пока объект не станет доступным:

public synchronized deleteObject() {
  while( isEmpty() ) {
    try {
      wait();
    } catch( Exception ex ) {
      ex.printStackTrace();
    }//catch
  }//while

  //actually do delete object.
  ...
}//met

и затем submitObject должен уведомить потоки в состоянии ожидания, выполнив:

public synchronized submitObject() {
  //do put object
  ...
  notifyAll();
}//met

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

Я бы синхронизировал по очереди объект в submitObject а также deleteObject методов и этого должно быть достаточно, а это означает, что:

public submitObject(Object o){
    synchronized (theQueue) {
        ...
    }
}

public deleteObject(int objectId){
    synchronized (theQueue) {
        ...
    }
}

То, что вы делаете, эквивалентно синхронизации методов (public synchronized method() синхронизируется с this какой твой queue локальная переменная), за исключением того, что вы должны помнить, что вам нужно делать это каждый раз, когда вы используете очередь. Было бы безопаснее синхронизировать методы отправки и удаления. Object o = new Object() из синхронизированного блока.

Другие вопросы по тегам