I'm new to java concurrent coding and encounter an issue. The following code cannot stop while it runs. Who can tell me why? Thanks
import java.util.concurrent.TimeUnit;
public class Test {
private static boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
System.out.println(Thread.currentThread());
System.out.println(stop);
while (!stop) {
}
}).start();
TimeUnit.SECONDS.sleep(1);
stop = true;
System.out.println(Thread.currentThread());
System.out.println(stop);
}
}
I also try to run the following code and it can stop. Who can tell me why? Thanks
import java.util.concurrent.TimeUnit;
public class Test {
private static boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
System.out.println(Thread.currentThread());
System.out.println(stop);
while (!stop) {
System.out.println(" ");
}
}).start();
TimeUnit.SECONDS.sleep(1);
stop = true;
System.out.println(Thread.currentThread());
System.out.println(stop);
}
}
Because you've not indicated to the compiler that stop might be changed and read by multiple threads:
private static boolean stop;
it is allowed to optimize this:
while (!stop) {
}
to
if (!stop) {
while (true) {
}
}
which will never stop if stop is initially false.
Declaring stop volatile:
private static volatile boolean stop;
disallows this optimization.
JVM typically optimizes your code before actually executing it. In your case, while(!stop){} gets optimized to while(true){}. This happens because you aren't explicitly accessing your static variable via synchronized function, and JVM assumes the variable won't change in Thread unsafe manner.
To avoid the optimization, place anything in your while loop. You could do something like:
while(!stop) {
try{
Thread.sleep(1); // You could also call any other function here.
}
catch(Exception e) { }
}
In this case, JVM wouldn't try to optimize, and your code will execute as expected.
EDIT:
While this does work currently, but based on comments, I concur that this can change in future versions (or in other parallel implementations of JDK/JVM). Declaring the variable as volatile is the best way to avoid that optimization.
Related
This question already has an answer here:
Why does Unsafe.fullFence() not ensuring visibility in my example?
(1 answer)
Closed 2 years ago.
As expected the reader thread in below program runs forever since it cached the stop flag(non-volatile) on its local processor's cache. Whereas, as soon as I uncomment the println on reader thread, the flag gets updated flag value and program stops. How this is possible as writer thread only writes flag to its own local cache and not yet flushed to main memory?
Note: running this program in MacBook Pro x86 architecture machine.
public class FieldVisibility {
boolean stop = false;
public static void main(String[] args) throws Exception {
FieldVisibility fv = new FieldVisibility();
Runnable writerThreadJob = () -> { fv.writer(); };
Runnable readerThreadJob = () -> { fv.reader(); };
Thread writerThread = new Thread(writerThreadJob);
Thread readerThread = new Thread(readerThreadJob);
readerThread.start();
try { Thread.sleep(2); } catch (InterruptedException e) {}
writerThread.start();
}
private void writer() {
stop = true;
}
private void reader() {
while (!stop) {
// System.out.println("stop is still false...");
}
}
}
Margaret Bloom and Peter Cordes already gave the answer in the comments section.
The JIT is allowed to hoist the stop variable out of the loop because it isn't volatile. This optimization is called loop invariant code motion.
So the following loop:
private stop;
private void reader() {
while (!stop) {
System.out.println("stop is still false...");
}
}
Can be transformed to:
private stop;
private void reader() {
if(stop) return;
while (true) {
System.out.println("stop is still false...");
}
}
And now it is obvious the loop will never end.
import java.lang.Thread;
import java.util.Scanner;
class Running extends Thread{
private boolean Run=true;
public void shutdown(){
Run=false;
}
public void run(){
while(Run){
for(int i=0;i<1000;i++){
System.out.println("Starting Counter:"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Volatile {
public static void main(String[] args) {
Running run1=new Running();
run1.start();
System.out.println("Press any key to stop thread execution");
Scanner sc=new Scanner(System.in);
sc.nextLine();
run1.shutdown();
}
}
I am using a volatile key word to stop the thread execution. But couldn't get the solution
What should I be doing to stop the thread execution?
So your post mentions the volatile keyword but I don't see it in the code you've posted. You need to make sure that Run is a volatile boolean so that it can be changed in the main thread and the other thread will see the changes.
private volatile boolean Run=true;
But I think the problem is that you are testing for this Run only in the outer while loop. Maybe you want it also in the inner counting loop. Something like:
for(int i = 0; i < 1000 && Run; i++) {
Right now, once the loop start counting it will have to finish before the Run boolean is checked. That may be 1000 seconds in the future.
You are using the right pattern, but apply it a bit wrong:
Your Runflag will only be checked after 1000 seconds, because it will only be checked after the for loop finished. Change your code to the following:
public void run(){
while(Run){
for(int i=0;(i<1000) && (Run == true);i++){
System.out.println("Starting Counter:"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Please note you will have to completely remove the while loop if you don't want your for loop to be executed endlessly effectively.
A time ago the thread was stopped simply by calling the Thread's stop() function. Nowadays, it's deprecated because it's unsecure, so you have to stop the Thread from the inside of the Thread. You'll find a good example here. Keep in mind that doing this doesn't stop immediately the thread, it just tells it's available for stopping and Android will stop it whenever it finds it necessary.
Your code stays in the for-loop for 1000 seconds until it finally reaches the while(run) branch again. I guess this is why its not working properly.
These is the sample .You can create a boolean field and check it inside run:
public class Sample implements Runnable {
private volatile boolean isRunning = true;
public void run() {
while (isRunning) {
//do work
}
}
public void kill() {
isRunning = false;
}
}
To stop it just call
sample.kill();
This should work.
I have been looking for ways to kill a thread and it appears this is the most popular approach
public class UsingFlagToShutdownThread extends Thread {
private boolean running = true;
public void run() {
while (running) {
System.out.print(".");
System.out.flush();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {}
}
System.out.println("Shutting down thread");
}
public void shutdown() {
running = false;
}
public static void main(String[] args)
throws InterruptedException {
UsingFlagToShutdownThread t = new UsingFlagToShutdownThread();
t.start();
Thread.sleep(5000);
t.shutdown();
}
}
However, if in the while loop we spawn another another object which gets populated with data (say a gui that is running and updating) then how do we call back - especially considering this method might have been called several times so we have many threads with while (running) then changing the flag for one would change it for everyone?
thanks
One approach with these problems is to have a Monitor class which handles all the threads. It can start all necessary threads (possibly at different times/when necessary) and once you want to shutdown you can call a shutdown method there which interrupt all (or some) of the threads.
Also, actually calling a Threads interrupt() method is generally a nicer approach as then it will get out of blocking actions that throw InterruptedException (wait/sleep for example). Then it will set a flag that is already there in Threads (which can be checked with isInterrupted() or checked and cleared with interrupted(). For example the following code can replace your current code:
public class UsingFlagToShutdownThread extends Thread {
public void run() {
while (!isInterrupted()) {
System.out.print(".");
System.out.flush();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) { interrupt(); }
}
System.out.println("Shutting down thread");
}
public static void main(String[] args)
throws InterruptedException {
UsingFlagToShutdownThread t = new UsingFlagToShutdownThread();
t.start();
Thread.sleep(5000);
t.interrupt();
}
}
i added a utlility class which essentially had a static map and methods.
the map was of type Long id, Thread thread. I added two methods one to add to the map and one to stop the thread via the use of interrupt. This method took the id as a parameter.
I also changed my loop logic from while true, too while ! isInterrupted. Is this approach ok or is this bad programming style/convention
thanks
Take a look at this simple Java program:
import java.lang.*;
class A {
static boolean done;
public static void main(String args[]) {
done = false;
new Thread() {
public void run() {
try {
Thread.sleep(1000); // dummy work load
} catch (Exception e) {
done = true;
}
done = true;
}
}.start();
while (!done);
System.out.println("bye");
}
}
On one machine, it prints "bye" and exits right away, while on another machine, it doesn't print anything and sits there forever. Why?
This is because your boolean is not volatile, therefore Threads are allowed to cache copies of it and never update them. I would recommend an AtomicBoolean - that will prevent any issues you may have.
public static void main(String args[]) {
final AtomicBoolean done = new AtomicBoolean(false);
new Thread() {
public void run() {
done.set(true);
}
}.start();
while (!done.get());
System.out.println("bye");
}
By the time the main program's while loop is reached (which is also a Thread), the new Thread might be finishing its run() where done flag is set to true. Just to confirm this, you can add a sleep in the run() before done is set to true and then see if your bye is displayed on other machine also. Hope this would help.
When I run the program it does not display "HIIII."
I am a novice (sort of) so please dont "hate".
Is my wait() statement wrong? Or what am I doing wrong?
Is it the ArrayIndexOutOfBounds catch clause? Please help!
[edit] oh so is it the main method?? that it doesnt do anything?
[edit] i know the wait and notify is wrong... please don't mention it.
//this is the whole class
import javax.swing.*;
import javax.swing.JOptionPane;
public class none {
static boolean game;
final static boolean on = true;
final static boolean off = false;
static boolean cheatMode;
public static void main(String[] args) {
game = on;
boolean tru = true;
try{
if(tru = Boolean.parseBoolean(args[0])){
cheatMode = on;
System.out.println("Cheats are on.");
}
}
catch(java.lang.ArrayIndexOutOfBoundsException e){
e.printStackTrace();
System.out.println("Ignore this error, it's from not running it on the command prompt.");
}
}
public class console extends Thread{
public void run(){
try{
wait();
JOptionPane.showMessageDialog(null,"HIIII");
}
catch(Exception e){
e.printStackTrace();
System.out.println("The console glitched...");
}
//hiiii
JOptionPane.showMessageDialog(null,"HIIII");
}
public class mainThingy extends Thread{
public void run() {
if(game = on)
notify();
}
}
}
}
There seems to be couple of issues
1) if(tru = Boolean.parseBoolean(args[0])){
Above statement is assignemt and not comparison. Use == operator.
2) Wait and notify should always be called from inside Synchronized blocks. Your code doesn't seem to be doing that.
I'd advise against the standard wait()-notify() structures. There are way better methods for this: the Java concurrency package.
Tutorial for Java Concurrency
API JavaDoc
JCIP, or Java Concurrency In Practice (Peierls, Bloch, Bowbeer, Holmes, Lea)
And as you seem to be in your first steps in learning Java, I'd suggest another two books:
Effective Java (Bloch)
Java puzzlers (Bloch, Gafter)
>java none true will print only Cheats are on. But your question is about printing Hiii. Isn't it ? You have got that in JOptionPane dialog inside the console class. Without initializing it how can you expect your program to print Hiii?. Also why have you written two public classes in one file ? When you are calling wait and nottify methods, you are also missing the synchronized statement. So when you start your threads console and mainThingy those will throw IllegalMonitorStateException anyways. So actually what are you trying to do ?
You main method doesn't actually start anything
wait and notify must be synchronized on the same monitor/lock
Your two threads are not sharing the same monitor/lock
if (game = on) in mainThingy is an assignment, not a check, it should be if (game == on)
UPDATE with Example
public class TestThread {
static boolean game;
final static boolean on = true;
final static boolean off = false;
static boolean cheatMode;
public static void main(String[] args) {
game = on;
boolean tru = true;
try {
if (args.length > 0) {
if (tru = Boolean.parseBoolean(args[0])) {
cheatMode = on;
System.out.println("Cheats are on.");
}
}
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
System.out.println("Ignore this error, it's from not running it on the command prompt.");
}
Console con = new Console();
con.start();
// Give time for the console thread to get started
do {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(TestThread.class.getName()).log(Level.SEVERE, null, ex);
}
} while (!con.isAlive());
System.out.println("Start main...");
Console.MainThingy main = new Console.MainThingy();
main.start();
}
public static class Console extends Thread {
// A shared lock that our two threads can communicate on...
public static final Object WAIT_LOCK = new Object();
public void run() {
try {
System.out.println("Waiting...");
// Must "own" the monitor before we can call wait
synchronized (WAIT_LOCK) {
WAIT_LOCK.wait();
}
JOptionPane.showMessageDialog(null, "HIIII");
} catch (Exception e) {
e.printStackTrace();
System.out.println("The console glitched...");
}
}
public static class MainThingy extends Thread {
public void run() {
if (game == on) {
// Must "own" the monitor before we can call notify
synchronized (WAIT_LOCK) {
System.out.println("Notify...");
WAIT_LOCK.notify();
}
}
}
}
}
}
Java Concurrency is fun, but it will bite you if you're not careful with it and treat it nicely.
Take a read through Currency in Java