Java синхронизируется на объекте

У меня к тебе большой вопрос. Как синхронизировать два разных метода из одного и того же класса, чтобы заблокировать один и тот же объект? Вот пример:

public class MyClass extends Thread implements Observer{
  public List<AnotherClass> myList = null;

  public MyClass(List<AnotherClass> myList){
    this.myList = myList;
  }

  public void run(){
    while(true){
       //Do some stuff 
       myList.add(NotImportantElement);
    }
  }

  public void doJob{
    for(int i=0; i<myList.size; i++){
      ElementClass x = myList.get(i);
      //Do some more stuff
    }
  }
}

Вопрос в том, как я могу остановить run() от доступа к myList при выполнении doJob и наоборот?

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

Как мне сделать блокировку? Спасибо!

LE

Хорошо, я понял концепцию блокировки, но теперь у меня есть другой вопрос.

Предположим, у меня есть класс с public static myList и только один экземпляр этого класса. Из этого экземпляра я создаю n случаи Thread которые берут каждый элемент этого списка и делают с ним что-то еще.

Теперь, в определенный момент, myList обновляется. Что происходит с теми потоками, которые уже обрабатывали элементы myList? Как я должен заблокировать доступ на myList при обновлении?

5 ответов

Решение

ПРИМЕЧАНИЕ. Этот код предполагает, что у вас есть только один экземпляр MyClass. в соответствии с вашим постом это звучит как случай.

public class MyClass extends Thread implements Observer{
  private List<AnotherClass> myList = null;
  private Object lock = new Object();

  public MyClass(List<AnotherClass> myList){
    this.myList = new ArrayList(myList);
  }

  public void run(){
    while(true){
       //Do some stuff 
       synchronized(lock) {
        myList.add(NotImportantElement);
       }
    }
  }

  public void doJob{
    synchronized(lock) {
      for(int i=0; i<myList.size; i++){
        ElementClass x = myList.get(i);
        //Do some more stuff
      }
    }
  }
}

РЕДАКТИРОВАТЬ: Добавлено создание копии списка, чтобы внешние объекты не могли изменить список в соответствии с JB Nizet

РЕДАКТИРОВАТЬ 2: Сделал переменные закрытыми, чтобы никто другой не мог получить к ним доступ

Вы можете:

  1. Объявить оба run а также doJobsynchronized, Это будет использовать this как замок;
  2. Объявить список как final и синхронизировать на нем. Это будет использовать список в качестве блокировки. Объявление поля блокировки как final это хорошая практика. Таким образом, некоторые методы вашего класса могут синхронизироваться на одном объекте, в то время как другие методы могут использовать другой объект для синхронизации. Это уменьшает конкуренцию за блокировку, но увеличивает сложность кода;
  3. Ввести явное java.util.concurrent.locks.Lock переменная и использовать ее методы для синхронизации. Это улучшит гибкость кода, но также увеличит сложность кода;
  4. Не делайте явной синхронизации вообще, а вместо этого используйте некоторую поточно-ориентированную структуру данных из JDK. Например, BlockingQueue или же CopyOnWriteArrayList, Это уменьшит сложность кода и обеспечит безопасность потоков.
  5. Используйте синхронизацию для чтения / записи в volatile поле. Смотрите это ТАК сообщение. Это обеспечит безопасность, но значительно увеличит сложность. На второй мысли, не делай этого:)

Объявите оба метода как synchronized чтобы заблокировать каждый экземпляр, или использовать synchronized(this){...} блокировать, чтобы сделать блокировку только на текущий экземпляр.

Вы можете добавить

синхронизированный

ключевое слово для обоих методов ИЛИ использовать

synchronized(Myclass.class) {
}

Первый по существу использует объект Myclass.class, но он не так детализирован, как последний.

synchronized(myList) {
    // do stuff on myList
}

Специальная документация: внутренние блокировки и синхронизация

Тем не менее, я призываю вас использовать потокобезопасную параллельную структуру данных для того, чего вы хотите достичь, чтобы избежать синхронизации себя и получить (намного) лучшую производительность: обзор одновременных пакетов

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