2013-11-09 4 views
5

Это для моего кирпича NXT.Синхронизация общей переменной среди потоков в DIFFERENT классах в java?

Предположим, у меня есть два РАЗЛИЧНЫХ класса, класс A и класс B, и каждый класс имеет поток OWN.

Однако существует статический экземпляр переменной с именем MotorA, который разделяется обоими классами. Эта переменная MotorA является ФИЗИЧЕСКИМ двигателем, движение которого может управляться двумя классами. Оба класса A и классы B могут управлять движением MotorA, но я хочу, чтобы только один из них мог управлять MotorA за раз.

Например, если класс A пытается повернуть MotorA вперед и класса B пытается повернуть MotorA назад, я только хочу класса A вращаться MotorA вперед и блок эффектов Класса Б.

Вопрос: Можно ли использовать SAME lock для синхронизации методов в потоках из DIFFERENT классов?

+0

Да, вы можете; каждый ресурс должен быть защищен только одним замком. (Хотя может быть лучше иметь класс, который инкапсулирует доступ к двигателю и его блокировку.) –

+0

Поскольку переменная двигателя разделяется между двумя потоками, «синхронизируйте» эту переменную двигателя, это совершенно законно. –

+0

, в то время как 'MotorA' является статическим, поэтому синхронизация метода не помогает (если только методы не являются статическими), вам нужно заблокировать переменную внутри метода. –

ответ

3

Да, вы можете. Вы действительно можете сделать это следующим образом:

class MotorA { 

    private static MotorA motor = new MotorA(); 
    private static final java.util.concurrent.locks.Lock lock = new java.util.concurrent.locks.ReentrantLock(); 

    private MotorA() { } 

    public static MotorA getMotorA() { 
    return motor; 
    } 

    public static Lock getLock() { 
    return lock; 
    } 

    /* here go business methods for MotorA */ 

} 

Далее, когда вы хотите сделать любую операцию, например Мотора, вам просто необходимо:

  • 1) восстановить свою блокировку на getLock()
  • 2) Вызов Lock.lock() по данному примеру
  • 3) приобрести Мотор одноэлементный по getMotorA()
  • 4) выполнить любой метод на MotorA instace
  • 5) Вызов Lock.unlock(), чтобы освободить замок.

В этом случае доступ к ресурсу будет безопасен из нескольких потоков.

Или вы можете просто синхронизировать на экземпляре Мотора:

class UserOfMotor1 { 

    public void doOperationInMotor1Thread() { 

     synchronized(MotorA.getMotorA()) { 

      MotorA motor = MotorA.getMotorA(); 
      motor.soSth(); 

     } 
    } 

    } 

Но в этом случае, вы также должны использовать synchronized() блок в каждый раз, когда поток использует общий ресурс - в вашем случае MotorA. Если вы используете этот метод управления синхронизацией, вы должны убедиться, что вы синхронизируете один и тот же объект в разных потоках - в этом случае MotorA - это Singleton, поэтому вы всегда получаете тот же экземпляр.

+0

Большое спасибо! Могу ли я добиться такого же эффекта, просто выбросив весь свой код внутри синхронизированного (lock) {} вместо того, чтобы делать блокировку и разблокировать? – user2973438

+0

Да. Но тогда это будет другой механизм, но все тот же результат. Вы можете синхронизировать() на любом объекте. В вашем случае было бы проще синхронизировать экземпляр MotorA. Lock.lock() - это другой механизм из synchronized(), хотя в большинстве случаев он делает то же самое. Это только вопрос предпочтения, который можно использовать, хотя Lock более гибкий, если у вас есть несколько синхронизированных блоков. –

+0

Привет, я все еще не совсем понимаю разницу между синхронизированными (это) и синхронизированными (MotorA). Какая разница в использовании фиктивного объекта в качестве синхронизированной блокировки, а не для использования фактического объекта, к которому я хочу получить эксклюзивный доступ? Спасибо! – user2973438

0

Вы можете написать методы класса A и B который синхронизирует на мьютекс называется motor, как показано ниже:

class A{ 

public void doSomething(){ 
    synchronized(MotorA.motor){ 
     //do what you want 
    } 
} 



class B{ 

public void doSomething(){ 
    synchronized(MotorA.motor){ 
     //do what you want 
    } 
} 

Вот класс для MotorA

class MotorA{ 
    public static MotorA motor=new MotorA(); 
    ...... 
    ...... 
    ...... 
} 

EDIT

Если у вас уже есть экземпляр и хотят поделиться среди класса A и B, чем вы можете передать объект в Constructure и синхронизации по объекту:

class A{ 
    final MutexObject mm; 
    public A(MutexObject m){ 
     mm=m; 
    } 
    public void doSomething(){ 
     synchronized(mm){ 
      //do what you want 
     } 
    } 



class B{ 
final MutexObject mm; 
public B(MutexObject m){ 
    mm=m; 
} 
public void doSomething(){ 
    synchronized(mm){ 
     //do what you want 
    } 
} 

Но будьте осторожны при прохождении объекта MutexObject в конструкторы из A и B, оно должно быть таким же, пример.

+0

Это работает, если MotorA на самом деле является INSTANCE другого класса под названием NXTRegulatedMotor? Этот класс не был изобретен мной, он поставляется с leJOS (виртуальная машина Java для NXT-кирпича, которую я пытаюсь запрограммировать!) Я имею в виду: NXTRegulatedMotor MotorA = Motor.A; – user2973438

+0

Это сработает, вам просто нужно убедиться, что вы используете один и тот же экземпляр среди классов 'A' и' B'. И синхронизируйте в одном экземпляре. Что еще нужно? – Trying

+0

большое спасибо !!! – user2973438

1

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

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

final class Locks { 

    public static final Object MOTORS = new Object(); 

    private Locks() { /* Disallow instantiation. */ } 

} 

Чтобы использовать его:

final class ThreadA extends Thread { 

    public void run() { 
    ... 
    synchronized(Locks.MOTORS) { 
     Motor motorA = Motors.A; 
     motorA.setSpeed(...); 
     ... 
    } 
    } 

} 

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

0

Это не прямой ответ на заданный вами вопрос, просто совет.

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

Я НИКОГДА не вижу больше классов (или методов), делая код более сложным - я слышал, что это может произойти, но я никогда его не видел. Сложность, которую я видел, всегда исходит от попытки сделать что-то, не создавая новых методов или классов.

Методы на вашем моторном классе также могут иметь больше смысла. Например (я не знаю, как это работает, поэтому я просто догадываюсь), если вы активируете двигатель, установив бит, вы можете выставить метод, например, «goForward (int speed)» и «goBack (int speed)», вместо «motor | = 0x10» или что-то неявное.

0

Вместо синхронизации в классе конечного пользователя (ClassA & ClassB) вы можете сделать это в своем классе motorA. Ответственность за синхронизацию своих действий должна отвечать классу MotorA.

Мотора класс:

public class MotorA { 

    private static MotorA instance = new MotorA(); 
    private static int pointer = 0; 

    private MotorA() { 
    } 

    public static MotorA getInstance() { 
     return instance; 
    } 


    public void rotate() { 
     synchronized(MotorA.class) { 
      System.out.println(Thread.currentThread() + " Rotating "+ pointer++); 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

Конечный пользователь класса Мотора - CLASSA & ClassB, который не знает много о существований других нитей.

public class ClassA implements Runnable { 

    @Override 
    public void run() { 
     doRotate(); 

    } 

    private void doRotate() { 
     MotorA motor = MotorA.getInstance(); 
     while (true) { 
      motor.rotate(); 
      try { 
       Thread.sleep(10); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 


public class ClassB implements Runnable { 

    @Override 
    public void run() { 
     doRotate(); 

    } 

    private void doRotate() { 
     MotorA motor = MotorA.getInstance(); 
     while (true) { 
      motor.rotate(); 
      try { 
       Thread.sleep(15); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

Здесь Главная программа.

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

     Thread a = new Thread(new ClassA()); 
     Thread b = new Thread(new ClassB()); 
     Thread c = new Thread(new ClassA()); 
     Thread d = new Thread(new ClassB()); 
     a.start(); 
     b.start(); 
     c.start(); 
     d.start(); 
    } 
} 
0

Как об этом:

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class Shared<T> { 
    private T _data; 
    private final Lock lock = new ReentrantLock(true); 

    public T getData() { 
     try { 
      lock.lock(); 
      return _data; 
     } finally { 
      lock.unlock(); 
     } 
    } 

    public void setData(T _data) { 
     try { 
      lock.lock(); 
      this._data = _data; 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

Использование:

Shared<Boolean> b = new Shared<Boolean>(); 
b.setData(true); 

//other thread 
while (b.getData()) { 
    ... 
} 
Смежные вопросы