2016-04-15 3 views
2

У меня есть основной поток и рабочий поток. Основной поток добавляет задачи в очередь, а рабочий поток принимает их для вычисления данных. Прежде чем помещать объекты в очередь, я вызываю блокировку объекта ReentrantLock (по основному потоку) внутри объектов задачи. Когда рабочий поток завершается работой над задачей из очереди, я вызываю разблокировку (на рабочий поток). Проблема в том, что я получаю исключение IllegalMonitorStateException, потому что я вызываю блокировку и разблокировку в разных потоках.Java lock and unlock on different thread

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

Пример:

public class Worker extends Thread { 
    public static Queue<Task> tasks = new ConcurrentLinkedQueue<Task>(); 

    @Override 
    public void run() { 
     while (true) { 
      Task task = tasks.poll(); 

      if (task != null) { 
       task.work(); 
       task.lock.unlock(); // Here is the unlock, Task#i should not change up to now 
      } 
     } 
    } 
} 


public class Task { 
    private int i = 0; 
    public Lock lock; 

    public void setI(int i) { 
     lock.lock(); 
     this.i = i; 
     lock.unlock(); 
    } 

    public void work() { 
     System.out.println(i); 
    } 
} 


public class Test { 
    Task task = new Task(); 

    public void addTask() { 
     task.lock.lock(); // Here is the lock, Task#i should not change 
     Worker.tasks.add(task); 
    } 
} 
+0

Что вы пытаетесь защитить своей блокировкой? – Savior

+0

@Pillar Данные внутри объектов. – stonar96

+0

синхронизировать объект перед блокировкой и разблокировкой – ControlAltDel

ответ

1

Почему бы не использовать Semaphore только с одним разрешением? Вместо операции блокировки вы получаете одно разрешение. Вы всегда должны освобождать блокировку с помощью release().

0

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

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

Я не думаю, что можно приобрести замок в одном потоке и разблокировать в другом.

+0

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

0

Вам не нужна альтернативная система блокировки. Структура данных ConcurrentLinkedQueue уже обеспечивает собственную систему блокировки и гарантирует безопасность потоков. Любая дополнительная блокировка не нужна.

Но вы заново изобретаете колесо здесь. Я бы посоветовал вам взглянуть на ExecutorService и ThreadPools. Хотя это хороший опыт обучения для создания вещей самостоятельно. Это также большой источник ошибок.

ExecutorService workerPool = Executors.newFixedThreadPool(10); // 10 worker threads 
... 
Runnable myTask = ...; 
workerPool.submit(myTask); // called from the main thread 
...