5

これは私のNXTブリック用です。

ClassAと Classの 2 つのB異なるクラスがあり、各クラスには独自のスレッドが実行されているとします。

MotorAただし、両方のクラスで共有される静的変数インスタンスが呼び出されます。このMotorA変数は、2 つのクラスによってモーションを制御できる PHYSICAL モーターです。ClassAと ClassBの両方のスレッドがMotorAの動きを制御できますが、一度に制御できるのはそのうちの 1 つだけですMotorA

たとえば、Classが前方Aに回転しようとしていて、Class が後方に回転しようとしている場合、Class のみが前方に回転して Class B の効果をブロックするようにします。MotorABMotorAAMotorA

質問: SAME ロックを使用して、異なるクラスのスレッド内のメソッドを同期できますか?

4

6 に答える 6

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 */

 }

次に、MotorA インスタンスで何らかの操作を実行する場合は、次のものが必要です。

  • 1) によってそのロックを取得しますgetLock()
  • 2) 指定されたインスタンスで Lock.lock() を呼び出します
  • 3) MotorAシングルトンを取得する getMotorA()
  • 4)インスタンスで任意のメソッドを実行しMotorAます
  • 5) Lock.unlock() を呼び出してロックを解除します。

この場合、リソースへのアクセスは複数のスレッドから安全になります。

または、MotorA のインスタンスで単純に同期することもできます。

  class UserOfMotor1 {

    public void doOperationInMotor1Thread() {

        synchronized(MotorA.getMotorA()) {

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

        }
    }

  }

ただし、この場合、synchronized()スレッドが共有リソースを使用するたびに block in を使用する必要もあります-あなたの場合はMotorA. 同期を制御するこの方法を使用する場合は、異なるスレッドの同じオブジェクトで同期していることを確認する必要があります。この場合MotorAは であるSingletonため、常に同じインスタンスを取得します。

于 2013-11-09T17:47:56.933 に答える
1

各スレッドはsynchronize、モーターのインスタンスを操作しながら、モーターのインスタンス上で実行できます。ただし、1 つのスレッドが複数のモーターを一緒に使用する場合は、各モーターでロックを取得する必要があります。次に、同期ブロックを入れ子にする順序について非常に注意する必要があります。そうしないと、断続的なデッドロックが発生します。

代わりに、すべてのモーターに単一のロックを使用し、そのロックを保持せずにモーターを使用しないことをお勧めします。モーターは静的リソースであるため、このロックも静的リソースである可能性があります。大規模なプログラムでは、独自のプライベート ロックを作成し、それにアクセスできるユーザーを慎重に制御する方が少し安全です。このコンテキストでは、すべてのコードがアクセスできるグローバル ロック変数を持つことはおそらく問題ありません。

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(...);
      ...
    }
  }

}

モーターだけに限定する必要はありません。重要なのは、ネストされたブロックを異なるオブジェクトで同期させないことです。これは、1 つのメソッドで直接発生するか、別のメソッドの同期ブロックから同期ブロックを使用して 1 つのメソッドを呼び出したために発生する可能性があります。

于 2013-11-09T18:34:09.077 に答える
0

ClassAにメソッドを記述し、以下のよう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();
    ......
    ......
    ......
}

編集

Aすでにインスタンスがあり、クラス間で共有したい場合Bは、オブジェクトをコンストラクションで渡し、オブジェクトを同期できます。

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のコンストラクタに渡すときは注意してください。同じインスタンスである必要があります。AB

于 2013-11-09T18:14:20.483 に答える
0

エンド ユーザー クラス (ClassA & ClassB) で同期する代わりに、motorA クラス自体で同期できます。そのアクションを同期させるのは、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();
            }
       }
   }

}

MotorA クラスのエンド ユーザー - 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();
    }
}
于 2013-11-10T08:31:42.823 に答える
0

これはあなたが尋ねた質問に対する直接的な回答ではなく、アドバイスです。

「モーター」自体をクラスにすることをお勧めします。他のクラスのどちらにもモーター変数自体の「制御」を与える必要はありません。両方ともモータークラスへの参照を持っているだけです。一連のコマンドが完了するまで 1 つのメソッドが制御を持ち、メソッドが戻ると制御を解放するように、モーター クラスの各メソッドを同期することができます。

クラス (またはメソッド) が増えてコードが複雑になるのを見たことがありません。私が見た複雑さは、新しいメソッドやクラスを作成せずに物事を行おうとすることに常に起因しています。

モーター クラスのメソッドも、より理にかなっています。たとえば(すみません、これがどのように機能するのかわかりませんので、推測です)ビットを設定してモーターをアクティブにすると、「goForward(int speed)」や「goBack(int speed)」などのメソッドを公開できます「motor|=0x10」またはそのようなあいまいなものの代わりに。

于 2013-11-09T20:07:37.037 に答える