5

这是给我的 NXT 砖的。

假设我有两个不同的类, ClassA和 Class B,每个类都有自己的线程运行。

MotorA但是,两个类共享一个名为的静态变量实例。这个MotorA变量是一个物理电机,它的运动可以由两个类控制。ClassA和 ClassB的线程都可以控制MotorA的运动,但我只希望它们MotorA一次控制一个。

例如,如果 ClassA试图MotorA向前旋转而 ClassB试图MotorA向后旋转,我只希望 Class向前A旋转MotorA并阻止 Class B 的效果。

问题:我可以使用 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()
  • MotorA4)在实例 上执行任何方法
  • 5) 调用 Lock.unlock() 释放锁。

在这种情况下,对资源的访问将不受多个线程的影响。

或者您可以简单地在 MotorA 的实例上进行同步:

  class UserOfMotor1 {

    public void doOperationInMotor1Thread() {

        synchronized(MotorA.getMotorA()) {

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

        }
    }

  }

但是在这种情况下,您还必须synchronized()在线程使用共享资源时使用 block in - 在您的情况下MotorA。如果你使用这种控制同步的方法,你必须确保你在不同线程中的同一个对象上同步——在这种情况下MotorASingleton你总是得到同一个实例。

于 2013-11-09T17:47:56.933 回答
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(...);
      ...
    }
  }

}

您不需要将自己限制在电机上;关键是不要让嵌套块在不同的对象上同步。这可能直接发生在一种方法中,或者因为您从另一种方法中的同步块调用具有同步块的方法。

于 2013-11-09T18:34:09.077 回答
0

您可以在 Class 中编写方法,AB在互斥锁上同步,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
    }
}

但是在将对象传递给andMutexObject的构造函数时要小心,它应该是同一个实例。AB

于 2013-11-09T18:14:20.483 回答
0

这不是对您提出的问题的直接回答,只是一些建议。

我建议你让你的“电机”本身成为一个类。您不必为其他任何一个类提供电机变量本身的“控制”,它们都具有对电机类的引用。您可以同步电机类上的每个方法,以便一个方法具有控制权,直到完成一系列命令,然后在方法返回时释放控制权。

我从来没有见过更多的类(或方法)使代码更复杂——我听说它会发生,但我从来没有见过。我看到的复杂性总是来自于尝试在不创建新方法或类的情况下做事。

您的电机类上的方法也更有意义。例如(对不起,我不知道它是如何工作的,所以我只是猜测)如果你通过设置一点来激活电机,你可以暴露像“goForward(int speed)”和“goBack(int speed)”这样的方法而不是“电机| = 0x10”或类似的晦涩难懂的东西。

于 2013-11-09T20:07:37.037 回答
0

无需在最终用户类(ClassA 和 ClassB)上进行同步,您可以在您的 motorA 类本身中进行同步。同步其动作应该是 MotorA 类的责任。

电机A类:

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

这个怎么样:

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()) {
  ...
}
于 2015-09-16T07:43:38.363 回答