这是我的NXT砖。
假设我有两个不同的类,类A
和类B
,并且每个类都运行其OWN线程。
但是,有一个名为MotorA
的静态变量实例由两个类共享。这个MotorA
变量是一个物理电机,其运动可以由两个类控制。类A
和类B
的线程都可以控制MotorA
的动作,但我只希望其中一个一次控制MotorA
。
例如,如果班级A
正在尝试向前转动MotorA
而班级B
正在尝试向后转动MotorA
,我只想要班级A
向前旋转MotorA
并阻止B类效果。
问题:我可以使用SAME锁同步来自DIFFERENT类的线程中的方法吗?
答案 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实例进行任何操作时,你只需要:
getLock()
getMotorA()
MotorA
instace 在这种情况下,对多个线程的访问将是安全的。
或者你可以简单地在MotorA的实例上进行同步:
class UserOfMotor1 {
public void doOperationInMotor1Thread() {
synchronized(MotorA.getMotorA()) {
MotorA motor = MotorA.getMotorA();
motor.soSth();
}
}
}
但在这种情况下,只要线程使用共享资源,您就必须使用synchronized()
块 - 在您的情况下MotorA
。如果使用这种控制同步的方法,则必须确保在不同线程中的同一对象上进行同步 - 在这种情况下MotorA
是Singleton
,因此您始终可以获得相同的实例。
答案 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)
您可以在类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();
......
......
......
}
修改强>
如果您已经有一个实例,并希望在类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
的对象传递给A
和B
的构造函数时要小心,它应该是同一个实例。
答案 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()) {
...
}