Synchronizing a shared variable among threads in DIFFERENT classes in java?
Synchronizing a shared variable among threads in DIFFERENT classes in java?
this is for my NXT brick.
Let's say I have two DIFFERENT classes, Class A
and Class B
, and each class has its OWN thread running.
However, there is a static variable instance called MotorA
that is shared by both classes. This MotorA
variable is a PHYSICAL motor whose motion can be controlled by the two classes. Both Class A
and Class B
's threads can control MotorA
's motion but I only want ONE of them to control MotorA
at a time.
For example, if Class A
is trying to rotate MotorA
forward and Class B
is trying to rotate MotorA
backward, I only want Class A
to rotate MotorA
forward and block Class B's effect.
Question: Can I use the SAME lock to synchronize methods in threads from DIFFERENT classes?
Answer by Artem Moskalev for Synchronizing a shared variable among threads in DIFFERENT classes in java?
Yes, you can. You can actually do it like this:
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 */ }
Next, when you want to do any operation on MotorA instance, you just need:
- 1) retrieve its lock by
getLock()
- 2) Call Lock.lock() on the given instance
- 3) acquire MotorA singleton by
getMotorA()
- 4) perform any method on
MotorA
instace - 5) Call Lock.unlock() to release the lock.
In this case, the access to the resource will be safe from multiple threads.
Or you can simply synchronize on the instance of MotorA:
class UserOfMotor1 { public void doOperationInMotor1Thread() { synchronized(MotorA.getMotorA()) { MotorA motor = MotorA.getMotorA(); motor.soSth(); } } }
But in this case, you will also have to use synchronized()
block in whenever thread uses the shared resource - in your case MotorA
. If you use this method of controlling synchronization, you must ensure that you are synchronizing on the same object in different threads - in this case MotorA
is a Singleton
so you always get the same instance.
Answer by Trying for Synchronizing a shared variable among threads in DIFFERENT classes in java?
You can write methods in Class A
and B
which synchronizes on the mutex called motor
as below:
class A{ public void doSomething(){ synchronized(MotorA.motor){ //do what you want } } class B{ public void doSomething(){ synchronized(MotorA.motor){ //do what you want } }
Here is the class for MotorA
class MotorA{ public static MotorA motor=new MotorA(); ...... ...... ...... }
EDIT
If you already have a instance and want to share among class A
and B
than you can pass the object in constructure and synchronize on the object:
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 } }
But be careful while passing the object of MutexObject
into the constructers of A
and B
, it should be same instance.
Answer by erickson for Synchronizing a shared variable among threads in DIFFERENT classes in java?
Each thread can synchronize
on the motor instance while its working with it. However, if one thread is going to be using multiple motors together, this would lead you to acquire locks on each motor. Then you'd have to be very careful about the order you nest your synchronized blocks, or you will have intermittent deadlocks.
Instead, I suggest that you use a single lock for all motors, and never use any motor without holding that lock. Since the motors are static resources, this lock could be too. In a big program, it would be a bit safer to create your own private lock, and carefully control who can access it. In this context, it's probably okay to have a global lock variable that any code can access.
final class Locks { public static final Object MOTORS = new Object(); private Locks() { /* Disallow instantiation. */ } }
To use it:
final class ThreadA extends Thread { public void run() { ... synchronized(Locks.MOTORS) { Motor motorA = Motors.A; motorA.setSpeed(...); ... } } }
You wouldn't need to limit yourself to just motors; the key is not to have nested blocks synchronizing on different objects. That might happen directly in one method, or because you call one method with a synchronized block from a synchronized block in another method.
Answer by Bill K for Synchronizing a shared variable among threads in DIFFERENT classes in java?
This is not a direct answer to the question you asked, just some advice.
I suggest you make your "Motor" a class in itself. You don't have to give either of your other classes "Control" of the motor variable itself, they just both have references to the motor class. You can synchronize each method on the motor class so that one method will have control until a sequence of commands is complete, then release control as the method returns.
I've NEVER see more classes (or methods) make code more complex--I've heard it can happen, but I've never seen it. The complexity I've seen always comes from trying to do things without creating new methods or classes.
The methods on your motor class can make more sense as well. For instance (Sorry, I have no idea how this works, so I'm just guessing) if you activate the motor by setting a bit, you can expose method like "goForward(int speed)" and "goBack(int speed)" instead of "motor|=0x10" or something obscure like that.
Answer by Sriram for Synchronizing a shared variable among threads in DIFFERENT classes in java?
Instead of synchronizing at the end user class (ClassA & ClassB), you can do it in your motorA class itself. It should be the MotorA class's responsibility to synchronize its actions.
MotorA class :
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(); } } } }
End user of the MotorA class - ClassA & ClassB which doesn't know much about the existences of the other threads.
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(); } } } }
Here the Main program.
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(); } }
Answer by Kilanny for Synchronizing a shared variable among threads in DIFFERENT classes in java?
How about this:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Shared { 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(); } } }
Usage:
Shared b = new Shared(); b.setData(true); //other thread while (b.getData()) { ... }
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment