Reputation: 1545
I want to share a variable between multiple threads like this:
boolean flag = true;
T1 main = new T1();
T2 help = new T2();
main.start();
help.start();
I'd like to share flag
between main and help thread where these are two different Java classes I've created. Is any way to do this? Thanks!
Upvotes: 36
Views: 147762
Reputation: 23
You can use lock variables "a" and "b" and synchronize them for locking the "critical section" in reverse order. Eg. Notify "a" then Lock "b" ,"PRINT", Notify "b" then Lock "a".
Please refer the below the code :
public class EvenOdd {
static int a = 0;
public static void main(String[] args) {
EvenOdd eo = new EvenOdd();
A aobj = eo.new A();
B bobj = eo.new B();
aobj.a = Lock.lock1;
aobj.b = Lock.lock2;
bobj.a = Lock.lock2;
bobj.b = Lock.lock1;
Thread t1 = new Thread(aobj);
Thread t2 = new Thread(bobj);
t1.start();
t2.start();
}
static class Lock {
final static Object lock1 = new Object();
final static Object lock2 = new Object();
}
class A implements Runnable {
Object a;
Object b;
public void run() {
while (EvenOdd.a < 10) {
try {
System.out.println(++EvenOdd.a + " A ");
synchronized (a) {
a.notify();
}
synchronized (b) {
b.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class B implements Runnable {
Object a;
Object b;
public void run() {
while (EvenOdd.a < 10) {
try {
synchronized (b) {
b.wait();
System.out.println(++EvenOdd.a + " B ");
}
synchronized (a) {
a.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
OUTPUT :
1 A
2 B
3 A
4 B
5 A
6 B
7 A
8 B
9 A
10 B
Upvotes: 2
Reputation: 338181
AtomicBoolean
The succinct Answer by NPE sums up your three options. I'll add some example code for the second item listed there: AtomicBoolean
.
You can think of the AtomicBoolean
class as providing some thread-safety wrapping around a boolean
value.
If you instantiate the AtomicBoolean
only once, then you need not worry about the visibility issue in the Java Memory Model that requires volatile
as a solution (the first item in that other Answer). Also, you need not concern yourself with synchronization (the third item in that other Answer) because AtomicBoolean
performs that function of protecting multi-threaded access to its internal boolean value.
Let's look at some example code.
Firstly, in modern Java we generally do not address the Thread
class directly. We now have the Executors framework to simplify handling of threads.
This code below is using Project Loom technology, coming to a future version of Java. Preliminary builds available now, built on early-access Java 16. This makes for simpler coding, with ExecutorService
being AutoCloseable
for convenient use with try-with-resources syntax. But Project Loom is not related to the point of this Answer; it just makes for simpler code that is easier to understand as “structured concurrency”.
The idea here is that we have three threads: the original thread, plus a ExecutorService
that will create two more threads. The two new threads both report the value of our AtomicBoolean
. The first new thread does so immediately, while the other waits 10 seconds before reporting. Meanwhile, our main thread sleeps for 5 seconds, wakes, changes the AtomicBoolean
object’s contained value, and then waits for that second thread to wake and complete its work the report on the now-altered AtomicBoolean
contained value. While we are installing seconds between each event, this is merely for dramatic demonstration. The real point is that these threads could coincidently try to access the AtomicBoolean
simultaneously, but that object will protect access to its internal boolean value in a thread-safe manner. Protecting against simultaneous access is the job of the Atomic…
classes.
try (
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
)
{
AtomicBoolean flag = new AtomicBoolean( true );
// This task, when run, will immediately report the flag.
Runnable task1 = ( ) -> System.out.println( "First task reporting flag = " + flag.get() + ". " + Instant.now() );
// This task, when run, will wait several seconds, then report the flag. Meanwhile, code below waits a shorter time before *changing* the flag.
Runnable task2 = ( ) -> {
try { Thread.sleep( Duration.ofSeconds( 10 ) ); } catch ( InterruptedException e ) { e.printStackTrace(); }
System.out.println( "Second task reporting flag = " + flag.get() + ". " + Instant.now() );
};
executorService.submit( task1 );
executorService.submit( task2 );
// Wait for first task to complete, so sleep here briefly. But wake before the sleeping second task awakens.
try { Thread.sleep( Duration.ofSeconds( 5 ) ); } catch ( InterruptedException e ) { e.printStackTrace(); }
System.out.println( "INFO - Original thread waking up, and setting flag to false. " + Instant.now() );
flag.set( false );
}
// At this point, with Project Loom technology, the flow-of-control blocks until the submitted tasks are done.
// Also, the `ExecutorService` is automatically closed/shutdown by this point, via try-with-resources syntax.
System.out.println( "INFO - Tasks on background threads are done. The `AtomicBoolean` and threads are gone." + Instant.now() );
Methods such as AtomicBoolean#get
and AtomicBoolean#set
are built to be thread-safe, to internally protect access to the boolean value nested within. Read up on the various other methods as well.
When run:
First task reporting flag = true. 2021-01-05T06:42:17.367337Z
INFO - Original thread waking up, and setting flag to false. 2021-01-05T06:42:22.367456Z
Second task reporting flag = false. 2021-01-05T06:42:27.369782Z
INFO - Tasks on background threads are done. The `AtomicBoolean` and threads are gone.2021-01-05T06:42:27.372597Z
Pro Tip: When engaging in threaded code in Java, always study the excellent book, Java Concurrency in Practice by Brian Goetz et al.
Upvotes: 1
Reputation: 272207
Both T1
and T2
can refer to a class containing this variable.
You can then make this variable volatile, and this means that
Changes to that variable are immediately visible in both threads.
See this article for more info.
Volatile variables share the visibility features of synchronized but none of the atomicity features. This means that threads will automatically see the most up-to-date value for volatile variables. They can be used to provide thread safety, but only in a very restricted set of cases: those that do not impose constraints between multiple variables or between a variable's current value and its future values.
And note the pros/cons of using volatile
vs more complex means of sharing state.
Upvotes: 42
Reputation: 1546
Using static
will not help your case.
Using synchronize
locks a variable when it is in use by another thread.
You should use volatile
keyword to keep the variable updated among all threads.
Using volatile is yet another way (like synchronized, atomic wrapper) of making class thread safe. Thread safe means that a method or class instance can be used by multiple threads at the same time without any problem.
Upvotes: 7
Reputation: 65793
In addition to the other suggestions - you can also wrap the flag in a control class and make a final instance of it in your parent class:
public class Test {
class Control {
public volatile boolean flag = false;
}
final Control control = new Control();
class T1 implements Runnable {
@Override
public void run() {
while ( !control.flag ) {
}
}
}
class T2 implements Runnable {
@Override
public void run() {
while ( !control.flag ) {
}
}
}
private void test() {
T1 main = new T1();
T2 help = new T2();
new Thread(main).start();
new Thread(help).start();
}
public static void main(String[] args) throws InterruptedException {
try {
Test test = new Test();
test.test();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Upvotes: 20
Reputation: 500167
To make it visible between the instances of T1
and T2
you could make the two classes contain a reference to an object that contains the variable.
If the variable is to be modified when the threads are running, you need to consider synchronization. The best approach depends on your exact requirements, but the main options are as follows:
volatile
;AtomicBoolean
;Upvotes: 8
Reputation: 361
Upvotes: 5