Взаимодействие между потоками JAVA или задачка 'Робот'
В процессе профессионально деятельности встретилась задачка. К своему стыду решить её на вскидку не смог :( Так что решил заполнить пробелы в знаниях статьей....Задачка
public class Main { public static void main(String[] args) { new Thread(new Leg("left")).start(); new Thread(new Leg("right")).start(); Thread.sleep(2000); } } class Leg implements Runnable{ private String name; public Leg(String name){ this.name = name; } @Override public void run() { while (true) { System.out.println(name); } } }
Решение I (wait/notify)
Для решения задачи будем использовать встроенные средства синхронизации потоков языка java - монитор и блоки synchronized. А также методы взаимодействия потоков (wait(), notify()).
Основное назначение перечисленных выше средств следующее:
Основное назначение перечисленных выше средств следующее:
- монитор - объект осуществляющий контроль доступа потоков к исполнению кода в критических секциях.
- блок synchronized - определяет границы критических секций монитора т.е участков кода в которых может исполнятся одновременно только один поток .
- метод wait - используется в критических секциях для остановки исполнения потока с освобождением блокировки монитора (т.е другой поток ожидающий входа в критическую секцию монитора после выполнения метода wait сможет начать исполнение критической секции монитора)
- метод notify - используется в критических секциях для восстановления работы одного из потоков остановленных в данном мониторе.
public class WaitNotifyMain { public static void main(String[] args) { Object monitor = new Object(); new Thread(new Leg("left",monitor)).start(); new Thread(new Leg("right",monitor)).start(); Thread.sleep(2000); } } class Leg implements Runnable{ private String name; private Object monitor; public Leg(String name,Object monitor){ this.name = name; this.monitor = monitor; } @Override public void run() { try{ while (true) { synchronized (monitor) { monitor.notify(); monitor.wait(); System.out.println(name); } } } catch (Exception e) { e.printStackTrace(); } } }
Решение II (Condition)
Решение основано на классе ReentrantLock который представляет собой “Усовершенствование synchronized java”, появившейся в jdk1.5
public class CoditionMain { public static void main(String[] args) { final Lock lock = new ReentrantLock(); final Condition monitor = lock.newCondition(); System.out.println("Hello world!!"); new Thread(new LegCodition("left", monitor,lock)).start(); new Thread(new LegCodition("right", monitor,lock)).start(); Thread.sleep(2000); } } class LegCodition implements Runnable{ private String name; private Condition monitor; private Lock lock; public LegCodition(String name, Condition monitor,Lock lock){ this.name = name; this.lock=lock; this.monitor = monitor; } @Override public void run() { lock.lock(); try { while (true) { monitor.signal(); monitor.await(); System.out.println(name); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
Решение III (Queue)
Это все лишь нестандартное применение шаблона producer-consumer на основе LinkedBlockingQueue
public class QueueMain { public static void main(String[] args){ LinkedBlockingQueue queueToLeft = new LinkedBlockingQueue(); LinkedBlockingQueue queueToRigth = new LinkedBlockingQueue(); queueToRigth.put(new Object()); new Thread(new LeftLeg("left", queueToLeft, queueToRigth)).start(); new Thread(new RightLeg("right", queueToLeft, queueToRigth)).start(); Thread.sleep(2000); } } class LeftLeg implements Runnable{ private String name; private LinkedBlockingQueue queueToLeft; private LinkedBlockingQueue queueToRigth; public LeftLeg(String name, LinkedBlockingQueue queueToLeft, LinkedBlockingQueue queueToRigth){ this.name = name; this.queueToLeft = queueToLeft; this.queueToRigth=queueToRigth; } @Override public void run() { try{ while (true) { synchronized (this) { Object obj=queueToRigth.take(); System.out.println(name); queueToLeft.put(queueToLeft); } } } catch (Exception e) { e.printStackTrace(); } } } class RightLeg implements Runnable{ private String name; private LinkedBlockingQueue queueToLeft; private LinkedBlockingQueue queueToRigth; public RightLeg(String name, LinkedBlockingQueue queueToLeft, LinkedBlockingQueue queueToRigth){ this.name = name; this.queueToLeft = queueToLeft; this.queueToRigth=queueToRigth; } @Override public void run() { try{ while (true) { synchronized (this) { Object obj= queueToLeft.take(); System.out.println(name); queueToRigth.put(queueToLeft); } } } catch (Exception e) { e.printStackTrace(); } } }
Ресурсы
1. Статья "Синхронизация потоков"2. Брюс Эккель. Философия Java = Thinking in Java. — 3-е изд. — СПб.: Питер, 2003. — 976 с. — ISBN 5-88782-105-1
3. Статья Использование языка Java для разработки параллельных приложений
Комментариев нет:
Отправить комментарий