在Java中的DIFFERENT类中的线程之间同步共享变量?

时间:2013-11-09 17:35:50

标签: java multithreading synchronization locking

这是我的NXT砖。

假设我有两个不同的类,类A和类B,并且每个类都运行其OWN线程。

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

例如,如果班级A正在尝试向前转动MotorA而班级B正在尝试向后转动MotorA,我只想要班级A向前旋转MotorA并阻止B类效果。

问题:我可以使用SAME锁同步来自DIFFERENT类的线程中的方法吗?

6 个答案:

答案 0 :(得分: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)通过getMotorA()
  • 获取MotorA单身人士
  • 4)在MotorA instace
  • 上执行任何方法
  • 5)调用Lock.unlock()释放锁定。

在这种情况下,对多个线程的访问将是安全的。

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

  class UserOfMotor1 {

    public void doOperationInMotor1Thread() {

        synchronized(MotorA.getMotorA()) {

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

        }
    }

  }

但在这种情况下,只要线程使用共享资源,您就必须使用synchronized()块 - 在您的情况下MotorA。如果使用这种控制同步的方法,则必须确保在不同线程中的同一对象上进行同步 - 在这种情况下MotorASingleton,因此您始终可以获得相同的实例。

答案 1 :(得分: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(...);
      ...
    }
  }

}

您不需要仅限于电机;关键是不要在不同的对象上同步嵌套块。这可能直接在一个方法中发生,或者因为在另一个方法中使用来自同步块的同步块调用一个方法。

答案 2 :(得分:0)

您可以在类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();
    ......
    ......
    ......
}

修改

如果您已经有一个实例,并希望在类AB之间共享,那么您可以在结构中传递对象并在对象上进行同步:

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的构造函数时要小心,它应该是同一个实例。

答案 3 :(得分:0)

这不是你问的问题的直接答案,只是一些建议。

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

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

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

答案 4 :(得分:0)

您可以在motorA类中自行完成,而不是在最终用户类(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();
            }
       }
   }

}

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

答案 5 :(得分: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()) {
  ...
}