Проблема многопоточности Java

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

Я хотел бы заблокировать объект после отправки его в очередь действий (так из моего основного потока).

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

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

Иллюстрация кода:

// THREAD 1
final Object object = getObjectFromSomeWhere(); 

// lock the object here

concurrentActionQueue.add(new Action() {
        @Override
        public void execute() {
          // will be executed from THREAD 2
          // do something with object

          //unlock here once the data is processed

        }

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

Есть ли способ сделать это без методов hardcoding lock() и unlock () для моего объекта ?

2 ответа

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

    // THREAD 1
    final Object object = getObjectFromSomeWhere(); 
    
    final CountDownLatch latch = new CountDownLatch(1);
    
    concurrentActionQueue.add(new Action() {
            @Override
            public void execute() {
              // will be executed from THREAD 2
              // do something with object
    
              latch.countDown();   
            }
    }
    
    latch.await();
    

    Если вы хотите заблокировать данные объекта от изменения из другого потока, но оставить выполнение потока доступным, вам нужно сделать это внутри вашего Objectкласса. Я считаю, что это не объект. Например, вы можете передать ссылку наThread, которые имеют доступ к объекту, и проверить внутри негоThread.currentThread() == mAllowedThread;, чтобы узнать, разрешен ли этот поток для изменения объекта.

    Кроме того, вы можете использовать некоторый OO-способ справиться с этим, например, сделать вас объект имеет пакет-локальные сеттеры и передать обертку, которая имеет доступ к сеттерам к действию. Трудно сказать, что является решением, потому что я не вижу реальной проблемы. Надеюсь, что некоторые из моих предложений могут помочь вам.

  2. Только общий рефренс между потоками является ваш объект, следовательно, для достижения блокировки вы должны изменить свой объект. Если вы не хотите изменять свой объект, вы можете написать один вспомогательный класс, который будет использовать защелку обратного отсчета для выполнения задачи. И передайте эту ссылку на вспомогательный класс среди всех ваших потоков.
    Смотрите, если это то, что вы ищете —

    final YourObject object = getObjectFromSomeWhere();
    
    class HelperObject {
    YourObject object;
    public HelperObject(YourObject object){
    this.object = object;
    }
     final CountDownLatch latch = new CountDownLatch(1);
       public void countDown(){
         latch.countDown(); 
       }
    
       public void await(){
        latch.await();
       }
    }
    
     concurrentActionQueue.add(new Action() {
        @Override
        public void execute() {
          // will be executed from THREAD 2
          HelperObject helperObj;// do something with object
    
          helperObj.countDown();   
        }
    }