Problem about shared variable between threads in Java(11) - java

maybe what I hope to express isn't so clearly,
the first case is a sample about when and how to use volatile, And to make the program run successfully, We need to add the volatile.
the second is in the hope to express that, even without the volatile, the program sitll run successfully.
And I hope to know why this will happen without ‘volatile’
In the first sample, a typical sample of using volatile
public static int num=1;
public static class MyThread extends Thread {
// flag
private boolean flag = false ;
public boolean isFlag() { return flag;}
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) { e.printStackTrace();
}
// change flag to true
this.flag = true ;
System.out.println("flag=" + flag);
this.flag=true;
}
}
// main
static void testWithOutVolatile(){
MyThread t=new MyThread();
t.start();
while(true) {
boolean is=t.flag;
if (is) {
System.out.println("run======");
}
}
}
After started, the main thread won't find the change of flag unless using volatile
However, in the sample, unexpectedly, thread2 got the change of flag, why this happen?
static int amb=0;
static void testSimple(){
Thread t1=new Thread(()->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
amb++;
});
Thread t2=new Thread(()->{while(true) {
if (amb == 0) {
System.out.println("no");
}
if (amb != 0) {
System.out.println("SUc");
break;
}
}});
t2.start();
t1.start();
}
And After a try, I find if I remove the code
if (amb == 0) {
System.out.println("no");
}
it will run as I thought, thread2 can't get the change.
Thanks for your answer, QwQ

May Be,
in the second case, the io statement refresh the buffer zone of Thread
Thread t2=new Thread(()->{while(true) {
System.out.println("no");
if (amb != 0) {
System.out.println("SUc");
break;
}
}});
if I use an io statement(Sout), it will work successfully.
In this way, I keep finding reasons in println
And I find the true reason
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
synchronized caused the switch of thread
and with the switch, the buffer zone of the thread was clear,
so thread2 read a new value

Related

Does lock.notify() gets executed only at the end of the loop in a thread

public class MyVisibility {
private static int count = 0;
private static Object lock = new Object();
public static void main(String[] args) {
new MyVisibility.thread1().start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return;
}
new MyVisibility.thread2().start();
}
static class thread1 extends Thread {
int i = 0;
#Override
public void run() {
super.run();
while (true) {
synchronized (lock) {
count++;
System.out.println("Thread one count is " + count);
try {
lock.wait();
System.out.println("i am notified");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count > 5) {
return;
}
}
}
}
static class thread2 extends Thread {
int i = 10;
#Override
public void run() {
super.run();
while (true) {
synchronized (lock) {
count++;
System.out.println("Thead 2 count is " + count);
lock.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count > 10) {
return;
}
}
}
}
}
In above code,
Current result on execution : I can see lock.notify() is getting called only after end of the while loop.
My assumption is Since lock.notify() is getting called immediately after count variable getting incremented, and immediately it should notify the waiting thread to resume its execution, instead after second thread completion of execution call is going for waiting thread to resume, what is the reason for this, can someone correct me what was wrong with my understanding.
Thank you.
Your deduction - "I can see lock.notify() is getting called only after end of the while loop" is not entirely correct. Try running multiple times, or put break point just after synchronized block of thread2, and then you will see thread1 "i am notified" being printed.
From documentation of notify() -
The awakened thread will not be able to proceed until the current
thread relinquishes the lock on this object
In your case before thread2 relinquishes lock and then thread1 acquires lock, thread2 acquires lock again by going into synchronized block.

Trying to Get Guarded Blocks to Work

I'm not understanding why my code is not working correctly. I expect the first Thread to wait for 4 seconds for the second Thread to set a shared boolean "joy" to true, then for the first Thread to print out "Joy has been achieved!".
When I run the code, I get this output:
"No Joy Yet..."
"Notifying Joy"
Then it freezes up and doesn't continue. If my understanding is correct, the notifyAll() method which is called from my notifyJoy() method should wake t1 up from its wait() and then, since the shared static boolean variable joy is now true, "Joy has been achieved!" should print to the console.
I'm working from Oracle's "The Java Tutorial", Chapter 13: here is a link to the specific section: Java Tutorial Website. I'm going off of what they have and making a little example but I can't seem to figure out what I'm doing wrong. Any help would be appreciated. Here is a complete copy of my code for your reference:
public class JoyTime {
public static void main(String[] args) {
JoyRider j1 = new JoyRider(false);
JoyRider j2 = new JoyRider(true);
Thread t1 = new Thread(j1, "J1");
Thread t2 = new Thread(j2, "J2");
t1.start();
try {
Thread.sleep(4000);
}
catch (InterruptedException e) {}
t2.start();
}
}
class JoyRider implements Runnable {
private static boolean joy = false;
private boolean flag;
public JoyRider(boolean flag) {
this.flag = flag;
}
#Override
public void run() {
synchronized(this) {
if (flag) {
notifyJoy();
}
else {
while (!joy) {
System.out.println("No Joy Yet...");
try {
this.wait();
}
catch (InterruptedException e) {}
}
System.out.println("Joy has been achieved!");
}
}
}
public synchronized void notifyJoy() {
System.out.println("Notifying Joy");
joy = true;
notifyAll();
}
}
You are calling wait() and notifyAll() on different monitors, and more specifically on the built-in monitors of the two different JoyRider instances.
If you introduce a dedicated lock object:
private static final Object LOCK = new Object();
and change your run() method a little:
synchronized (LOCK) {
if (flag) {
System.out.println("Notifying Joy");
JOY = true;
LOCK.notifyAll();
}
else {
while (!JOY) {
System.out.println("No Joy Yet...");
try {
LOCK.wait();
}
catch (InterruptedException e) {}
}
System.out.println("Joy has been achieved!");
}
}
you should be able to see all the expected prints in the correct order.

Make even and odd threads to print numbers in natural order in Java

I know this question has been asked before, But I am unable to figure out why my solution is not working for me. I have two threads even and odd, one prints even numbers and other prints odd numbers. When I start the threads I want the output to be in natural order of numbers like 0 1 2 3..etc. This is my code:-
[updated]
public class ThreadCommunication {
public static void main(String... args) throws InterruptedException
{
final ThreadCommunication obj = new ThreadCommunication();
Thread even = new Thread(){
#Override
public void run()
{
for(int i=0;i<10;i=i+2){
synchronized(obj){
System.out.println(i);
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
};
Thread odd = new Thread(){
#Override
public void run()
{
for(int i=1;i<10;i=i+2){
synchronized(obj){
System.out.println(i);
obj.notify();
}
}
}
};
even.start();
odd.start();
}
}
when I run the above code, sometimes it prints the numbers in natural order as expected but sometimes it prints in some other order for ex:
0
1
3
5
7
9
2
What am I doing wrong here?
Edit:
volatile static boolean isAlreadyWaiting = false;
Thread even = new Thread() {
#Override
public void run() {
synchronized (obj) {
for (int i = 0; i < 10; i = i + 2) {
System.out.println(i);
try {
if (!isAlreadyWaiting) {
isAlreadyWaiting = true;
obj.wait();
}
obj.notify();
isAlreadyWaiting=false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Thread odd = new Thread() {
#Override
public void run() {
synchronized (obj) {
for (int i = 1; i < 10; i = i + 2) {
System.out.println(i);
try {
if(isAlreadyWaiting){
obj.notify();
isAlreadyWaiting = false;
}
if (!isAlreadyWaiting) {
isAlreadyWaiting = true;
obj.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Check documentation
public class IllegalMonitorStateException extends RuntimeException
Thrown to indicate that a thread has attempted to wait on an object's
monitor or to notify other threads waiting on an object's monitor
without owning the specified monitor.
Monitor is owned by obj
So you should call
obj.wait();
and
obj.notify();
For more info on Ownership
This methods (wait or notify) should only be called by a thread that
is the owner of this object's monitor. A thread becomes the owner of
the object's monitor in one of three ways:
By executing a synchronized instance method of that object.
By executing the body of a synchronized statement that synchronizes
on the object.
For objects of type Class, by executing a synchronized static method
of that class.
Only one thread at a time can own an object's monitor.
#Pragnani Kinnera is right about the exception you're seeing. But if you want to alternate between even and odd, you'll need to move your second synchronized block into the loop. Otherwise, the notifying thread will hold the lock exclusively until the loop completes. (As opposed to the first thread, which yields its lock on each round.)
Thread odd = new Thread(){
#Override
public void run()
{
for(int i=1;i<10;i=i+2){
synchronized(obj){
System.out.println(i);
notify();
}
}
}
};
The first thread, however, should have the loop inside the synchronized block. If both threads release the lock, they both have an equal chance at reacquiring it. But if the first loop is inside the synchronized block, the second thread won't be able to reenter until the first has completed a full round and is waiting once again.
EDIT: This still won't work correctly, because there is no guarantee that the first thread won't reacquire the lock before the second thread does, per this quote from the documentation:
The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
You'll probably want to wake and notify from both threads to ensure they're in sync.
Here is your solution:
public class ThreadCommunication {
public static void main(String args[]) throws InterruptedException
{
final ThreadCommunication obj = new ThreadCommunication();
Thread even = new Thread("Even Thread"){
#Override
public void run()
{
for(int i=0;i<10;i=i+2){
System.out.println(i);
synchronized(obj){
obj.notify();
}
synchronized(obj){
try {
obj.wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Thread odd = new Thread(){
#Override
public void run()
{
for(int i=1;i<10;i=i+2){
try {
synchronized(obj){
obj.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
synchronized(obj){
obj.notifyAll();
}
}
}
};
even.start();
odd.start();
}
}
As explained by #shmosel, your synchronized block should only contain code that need to be synchronized.

Two threads accessing same variable lock application

The following code was summed up the application, the application randomly was locked in
while (flag)
This code, running on my machine gets caught, in another machine he finished normally
The output generated here is:
INIT
END
before while
before flag
after flag
Code:
package threads;
public class Run implements Runnable {
private Thread thread;
private boolean flag = true;
public void init() {
thread = new Thread(this);
thread.setName("MyThread");
thread.start();
}
#Override
public void run() {
try {
int i = 0;
while (i < 1000) {
i++;
}
System.out.println("before flag");
flag = false;
System.out.println("after flag");
} catch (Exception e) {
e.printStackTrace();
} finally {
flag = false;
}
}
public void end() {
thread.interrupt();
thread = null;
System.out.println("before while");
while (flag) {
// try { Thread.sleep(100);} catch (InterruptedException e) {}
}
;
System.out.println("after while");
}
public static void main(String[] args) {
Run r = new Run();
System.out.println("INIT");
r.init();
System.out.println("END");
r.end();
}
}
Why when I change the value of flag the main thread does not pass through loop?
Change
private boolean flag = true;
to
private volatile boolean flag = true;
Without volatile, there is no guarantee the waiting thread needs to see the value get updated. HotSpot might even inline while(flag) to while(true) if the loop spins enough times.
See Memory Consistency Errors.
Also, what you're doing is called a spinlock. Normally you should use thread.join() instead. A spinlock is wasteful of resources because the waiting thread is actually working (checking a variable) the entire time it is supposed to be waiting.

Various way to stop a thread - which is the correct way

I had came across different suggestion of stopping a thread. May I know, which is the correct way? Or it depends?
Using Thread Variable http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
thisThread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
Using boolean flag
private volatile boolean flag;
public void stop() {
flag = false;
}
public void run() {
while (flag) {
try {
thisThread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
Using Thread Variable together with interrupt
private volatile Thread blinker;
public void stop() {
blinker.interrupt();
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (!thisThread.isInterrupted() && blinker == thisThread) {
try {
thisThread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
None of these is the "correct" way, they're all valid. Which one you use depends on your circumstances, and which one works best for you.
As long as you don't use Thread.stop(), and you tidy up any resources left open by your threads (connections, temp files, etc), then it doesn't really matter how you go about it.
I always use the boolean flag - its the simplest.
Its really short and easy to understand for reviewers, but it has the handycap that you can't interrupt the sleep call. You should only use the interrupt variants for time-critical thread stopping. And, like skaffman said - Don't use Thread.stop()!
what about this
class Tester {
public static void main() {
Try t = new Try();
Thread.sleep(10); //wait for 10 milliseconds
t.interrupt(); // 'interrupt' i.e stop the thread
}
}
public class Try extends Thread {
#override
public void interrupt() {
//perform all cleanup code here
this.stop();
/*stop() is unsafe .but if we peform all cleanup code above it should be okay ???. since thread is calling stop itself?? */
}
}

Categories

Resources