This question already has answers here:
What's the difference between Thread start() and Runnable run()
(14 answers)
Closed 6 months ago.
I am new to Java, I have want to starts 02 thread to increase an attribute of an object and I want to print out the value of this attribute until it reach a certain value.
I use 02 threads started inside increaseByThread() method.
I use two code snippets as follows but they behave differently.
The first one I use while loop in the main thread to check for the value change but it only print out the last value after two sub-threads finish running and return 40.
The second one I use while loop but inside another sub-thread for checking value and it prints out every value, it means that 03 sub-threads are running in parallel (please see the second snippet below)
My question is that why in the first snippet, the while loop block only called after test.increaseByThread() finish execution?
public class ThreadIncrease {
public volatile int[] count={0};
public void increaseByThread(){
Runnable first= () -> {
for(int i=0;i<20;i++) {
count[0] = count[0] + 1;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println(count[0]);
}
};
Runnable second= () -> {
for(int i=0;i<20;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count[0] = count[0] + 1;
// System.out.println(count[0]);
}
};
Thread firstThread=new Thread(first);
Thread secondThread=new Thread(second);
firstThread.run();
secondThread.run();
}
public static void main(String[] args) {
ThreadIncrease test=new ThreadIncrease();
Runnable check=()->{
while(true){
System.out.println(test.count[0]);
if(test.count[0]<10){
System.out.println("count is: "+test.count[0]);
}
else{
System.out.println("Break");
break;
}
}
};
// Thread checkThread=new Thread(check);
// checkThread.start();
test.increaseByThread();
while(true){
System.out.println(test.count[0]);
if(test.count[0]<10){
System.out.println("count is: "+test.count[0]);
}
else{
System.out.println("Break");
break;
}
}
}
}
The second one I use while loop but inside another sub-thread for checking value and it prints out every value, it means that 03 sub-threads are running in parallel:
public class ThreadIncrease {
public volatile int[] count={0};
public void increaseByThread(){
Runnable first= () -> {
for(int i=0;i<20;i++) {
count[0] = count[0] + 1;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println(count[0]);
}
};
Runnable second= () -> {
for(int i=0;i<20;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count[0] = count[0] + 1;
// System.out.println(count[0]);
}
};
Thread firstThread=new Thread(first);
Thread secondThread=new Thread(second);
firstThread.run();
secondThread.run();
}
public static void main(String[] args) {
ThreadIncrease test=new ThreadIncrease();
Runnable check=()->{
while(true){
System.out.println(test.count[0]);
if(test.count[0]<10){
System.out.println("count is: "+test.count[0]);
}
else{
System.out.println("Break");
break;
}
}
};
Thread checkThread=new Thread(check);
checkThread.start();
test.increaseByThread();
// while(true){
// System.out.println(test.count[0]);
// if(test.count[0]<10){
// System.out.println("count is: "+test.count[0]);
// }
// else{
// System.out.println("Break");
// break;
// }
// }
}
}
You have not started any new thread yet.
Each thread needs to run something. That is it's run method. But by invoking thread.run you just execute that code on the calling thread, which is your main thread.
Instead you need to start the new thread using thread.start(). This function will return immediately, and the newly created thread will execute run() in parallel.
Since you were running everything on the main thread the perception is right that the main thread was blocked until all the runs finished.
Thread.run(), which you are calling in increaseByThread() runs the Thread's Runnable in the current thread. I think you have confused it with Thread.start(), which starts a new thread to run the Runnable.
See What's the difference between Thread start() and Runnable run() and When would you call java's thread.run() instead of thread.start()?
Related
This question already has answers here:
Why is this code working without volatile?
(2 answers)
Closed 2 years ago.
I'm playing with volatile keyword in Java and I have this code that tries to show that a thread doesn't see changes introduced by another thread unless we declare data as volatile. I was expecting that the code below will never terminate as I haven't declared the shared data as volatile. Any ideas why this code actually terminates?
public class VolatileTest {
public static void main(String[] args) throws InterruptedException {
var holder = new Holder();
new Thread(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) { }
for(int i = 0; i<100000; i++) {
holder.counter++;
}
}).start();
var t = new Thread(() -> {
while(holder.counter < 10000) {
System.out.println("Jestem w pętli");
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
t.join();
}
static class Holder {
int counter = 0;
}
}
Thread 1 MAY not see change from the Thread 2 immediately if you don't use volatile, but eventually once in the future, that will happen when Thread 2 empty CPU cache to main memory. In your example, if you use volatile on counter field, writing thread will always write to main memory when you call holder.counter++ and reading thread will read from main memory every time you call holder.counter < 10000.
import java.io.IOException;
public class Test implements Runnable {
private int m, n;
public synchronized void run() {
try {
for (int i = 0; i < 10; i++) {
m++;
n++;
Thread.sleep(100);
System.out.println(m + ", " + n);
}
} catch (InterruptedException e) {
}
}
public static void main(String[] args) {
try {
Test a = new Test();
new Thread(a).start();
new Thread(a).start();
} catch (Exception e) {
}
}
}
You are correct that you cannot start the same thread twice. But you aren't doing that here. You are starting two separate threads once each.
Your code is essentially the same as:
Thread t1 = new Thread(a);
t1.start();
Thread t2 = new Thread(a);
t2.start();
You are declaring 2 different threads and running them one after another. If you add the following code.
public synchronized void run() {
System.out.println("thread started");
try {
for (int i = 0; i < 10; i++) {
m++;
n++;
Thread.sleep(100);
System.out.println(m + ", " + n);
}
} catch (InterruptedException e) {
}
System.out.println("thread fininshed");
}
You can easily see where the first thread ends and then the second thread starts.
Each of your threads needs to execute task described in instance of Test class. More precisely in its run method. In your case both threads will need to execute task of Test but they will also need to use same instance of this class (which is stored in a reference).
Problem is that run method is synchronized which means it uses monitor/lock of current instance (this - available via a reference) which means that both threads can't execute it at the same time. To be more precise one of threads will need to wait until other thread will finish execution code from that synchronized block (which is entire body of run).
So in your case
one of your threads will print
enter synchronized block locked on a
print values in range 1-10
exit synchronized block locked on a
so now another thread can
enter synchronized block locked on a
print values in range 11-20 (since m and n will be increased each time in loop)
exit synchronized block locked on a
I am new to java and I am trying to learn about threads.
I am expecting an output of alternate hello this is thread one and hello this is thread two. but the output I get is as follows:
hello this is thread one
hello this is thread one
hello this is thread one
hello this is thread one
hello this is thread one
hello this is thread two
hello this is thread two
hello this is thread two
hello this is thread two
hello this is thread two
Below is my code. Can anyone please help me out to why I am getting this output as opposed to expected. And what is it that I can do to run the two threads in parallel.
public class ThreadDemo {
public static void main(String args[]) {
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread one");
}
}
};
// This is the second block of code
Thread threadTwo = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread two");
}
}
};
// These two statements are in the main method and begin the two
// threads.
// This is the third block of code
thread.start();
// This is the fourth block of code
threadTwo.start();
}
}
Just because threads may interlace does not mean that they will. Your threads simply run too fast. Try adding Thread.sleep() to make them run longer.
The problem here is that PrintStream is synchronized which is not fair.
final Lock lock = new ReentrantLock(true); //create fair lock
//after running this code change it to
//ReentrantLock(false); to see what happens
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
lock.lock();
System.out.println("hello this is thread one");
lock.unlock();
}
}
};
// This is the second block of code
Thread threadTwo = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
lock.lock();
System.out.println("hello this is thread two");
lock.unlock();
}
}
};
// These two statements are in the main method and begin the two
// threads.
// This is the third block of code
thread.start();
// This is the fourth block of code
threadTwo.start();
when a lock is fair it will be alot slower, but when its not fair as in your first case it keeps grabbing the lock over and over before the other thread gets a chance to take it. A fair lock is like a queue. Whoever is queued to take it next gets it.
Depending on the number of CPUs and/or CPU cores, multi-threading may only be simulated by your CPU by giving each thread a certain number of time before another thread is scheduled. See also Wikipedia on "Preemptive Multitasking"
Also, given today's CPUs and many cores and their speed, it may also be that the execution of the first thread already finished before the second one is started.
Also, both threads are battling for the lock in System.out, so they will lock each other out.
Let the threads run for longer times (higher number of iterations), and you will see the interleaving you are expecting.
Your code would work too..add sleep in the first object.
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread one");
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
If you want to have the threads' bodies wait until both threads are running, you can use something like a CountDownLatch, which can block until its internal counter counts down to zero:
final CountDownLatch latch = new CountDownLatch(2);
Thread thread = new Thread() {
#Override public void run() {
latch.countDown();
latch.await(); // Execution waits here until latch reaches zero.
// Rest of the method.
}
}
Thread threadTwo = new Thread() {
#Override public void run() {
latch.countDown();
latch.await(); // Execution waits here until latch reaches zero.
// Rest of the method.
}
}
thread.start();
threadTwo.start();
(Exception handling omitted for clarity)
This will guarantee that the "interesting bit" of the two threads' run methods will be executing at the same time. However, because of the unfair synchronization on the println() method you are calling, there is no guarantee of how the messages printed by the two threads will be interleaved:
Sometimes they might "perfectly" interleave (1, 2, 1, 2, ...)
Sometimes a few of one might be printed without anything from the other (1, 1, 2, 1, 2, 2, 2, ...)
Sometimes one might print all of its messages before the other (1, 1, 1, 1, 2, 2, 2, 2).
Below code is working...
public class ThreadDemo {
public static void main(String args[]) throws InterruptedException {
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread one");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
// This is the second block of code
Thread threadTwo = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread two");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
// These two statements are in the main method and begin the two
// threads.
// This is the third block of code
thread.start();
// This is the fourth block of code
threadTwo.start();
}
}
Your code is working as expected, there is absolutely no guarantee that your implementation will execute in the pre-defined manner you are expecting.
I would suggest that you look at other methods of implementing multithreaded code such as join(), sleep() and finding one that better suits your needs.
I am trying to understand volatile usage by the below example. I expect it to print 10 first and then 15 second. But most of the time i end getting 10 and 10.
Is some thing with the below code itself.
class T implements Runnable {
private volatile int x = 10;
#Override
public void run() {
if(x==10) {
System.out.println(x);
x = x+ 5;
} else if(x==15) {
System.out.println(x);
}
}
}
public class Prep {
public static void main(String [] args) {
T t1 = new T();
new Thread(t1).start();
new Thread(t1).start();
}
}
You just have a race condition: both threads run in parallel, and thus you have (for example)
thread 1 tests if x == 10 (true)
thread 2 tests if x == 10 (true)
thread 1 prints 10
thread 2 prints 10
...
The fact that x is volatile here is irrelevant. The only thing that volatile guarantees in this example is that if thread 1 has already incremented x when thread 2 reads its value, then thread 2 will see the incremented value. But it doesn't mean that the two threads can't run in parallel as shown above.
This will work :
public static void main(String[] args) {
T t1 = new T();
new Thread(t1).start();
try {
Thread.currentThread().sleep(1000); // sleeping for sometime .
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(t1).start();
}
answer : 10 15
Reason : The operations
if(x==10) {
System.out.println(x);
might have executed first for the first thread, then context would have switched back to Thread2 (race condition as JB Nizet explains..) so when both threads print the value of x, it is still 10.
I am just wondering how to control console inputs in separate threads?
I have thread A and thread B and thread C; B and C they both control user input... the thing is I am not pretty sure how to switch between B and C threads the scanIn.nextLine(); because B seems to loop two unnecessary iterations before thread C can interrupt B :(
Main thread:
public class Main
{
private volatile ThreadGroup threadGroup=new ThreadGroup();//contains concurrent hash map...
private volatile TaskManager taskManager=new TaskManager(threadGroup);
private A a=new A(threadGroup);
private B b=new B(threadGroup,taskManager);
private C c=new C(threadGroup);
Main()
{
b.start();
threadGroup.add(a,"A");
threadGroup.add(b,"B");
threadGroup.add(c,"C");
}
public static void main(String args[]){new Main();}
}
TaskManager method snippet:
...
public synchronized void threadCMaybeCanBeStartedLater()
{
this.getThreadGroup().get("A").start();
}
...
thread A code like a (overridden run method invokes):
public void loopIt()
{
Random generator = new Random();
A: while(!this.interrupted())
{
Thread.sleep(1000);
int i=generator.nextInt(100)+1;
int j=generator.nextInt(100)+1;
if(i==j){this.invokeC(); System.out.println("event : i==j");}
}
}
private void invokeC()
{
if(!this.getThreadGroup().get("C").isAlive())this.getThreadGroup().get("C").start();
}
thread B code like a:
public void loopIt() throws InterruptedException
{
Scanner scanIn = new Scanner(System.in);
B: while(!this.isInterrupted())
{
Thread.sleep(1000);
String command= scanIn.nextLine();
...
if(command.equals("a"))
{
System.out.println("a was entered");
this.getTaskManager().threadCMaybeCanBeStartedLater();//
continue;
}
if(command.equals("b"))
{
System.out.println("b was entered");
continue;
}
if(command.equals("c"))
{
System.out.println("c was entered");
continue;
}
else{System.out.println("no such command");}
}
}
thread C (the run method invokes)
public void loopIt() throws InterruptedException
{
getThreadGroup().get("B").interrupt();
Scanner scanIn = new Scanner(System.in);
C: while(!this.isInterrupted())
{
Thread.sleep(1000);
String command= scanIn.nextLine();
...
if(command.equals("d"))
{
System.out.println("d was entered");
continue;
}
if(command.equals("e"))
{
System.out.println("e was entered");
this.interrupt();
break C;
}
if(command.equals("f"))
{
System.out.println("f was entered");
continue;
}
else{System.out.println("no such command");}
}
getThreadGroup().get("B").start();
}
...as you can see, the major code conception (see A thread snippet) is "you don't know when thread C can be started but when it started you need to give it console"; that's all; if it was GUI there was no problem but console-like app makes it quite problematic...
So the question is ... how to interrupt/re-start thread B immediately from thread C in this case?
Thanks
Synchronising Threads Using Thread Class
Thread.interrupt() on its own does not synchronise logic & timing between two threads.
Thread.interrupt() signals that the caller would like the thread to interrupt at a time in the near future. The interrupt() method sets an interrupt flag. The isInterrupted() method checks whether this flag is set (& also clears the flag again). The methods Thread.sleep(), Thread.join(), Object.wait() and a number of I/O methods also check & clear this flag, when throwing InterruptedException.
The thread doesn't immediately pause but continues running code. The internal thread logic is designed & implemented by the developer: continue to run thread code considered atomic/urgent until it gets to an "interruptable point", then check the interrupted flag / catch InterruptedException & then do a clean pause - usually via Thread.sleep(), Thread.join() or Object.wait(), and sometimes by exiting Thread.run() altogether thus stopping the thread permanently.
While all of this is happening the calling thread is still running and will execute an indeterminate amount of code before the interrupt takes effect... hence the lack of synchronisation. There is a lack of guaranteed happens-before condition between the code in one thread and code in the other thread.
Some approaches that do synchronise logic & timing between two threads (creating a happens-before condition):
thread1 calls Thread2.join()
thread1 calls SomeObject.wait() and thread2 calls SomeObject.notify()
Synchronise on a method or block
Quick Review of Your Code:
Thread B runs in an infinite loop - there is no call to interrupt it from any thread and no call for it's thread to wait(). It will, however, temporily block until System.in has more input, and then continue.
Thread A only interrupts itself - cleaner and easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (i != j)
Thread A only interrupts itself - cleaner and much easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (!"e".equals(command))
Thread C must make the following calls at the top of it's while loop:
threadB.interrupt();
synchronized(this) {
try {
this.wait();
} catch (InterruptedException ie) {
}
Thread B must make the following call as the last line of code:
synchronized(threadC) {
threadC.notify();
}
Reading from I/O (nextLine()) is a blocking & interruptable operation. Right next to it you introduce Thread.sleep() which is also a blocking & interruptable operation that introduces an artificial delay in your code - it is not necessary; remove.
The only Scanner method you call is nextLine(). You're using it as if it were an InputStreamReader & not doing any scanning. Also, you're not buffering input. If code stays like this, replace 'Scanner scanIn = Scanner(System.in)' with: 'BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))'.
The only ThreadGroup method you call are add() and get(). You're using it as if it were a HashMap & not doing any thread group management. If code stays like this, you may replace 'ThreadGroup' with 'HashMap'. However, even the HashMap seems excessive - could simply pass Threads references to other Threads using constructors/setters and avoid HashMap altogether.
Avoid excessive use of continue inside loops - try to avoid altogether. Best to do this by chaining successive 'if' statements together using '} else if {'...
Potential race condition between main thread and thread B. When thread B is started (from Main()) it may execute many lines of code before the main thread executes any more code - B may call ThreadGroup.get() before main thread has called ThreadGroup.add() x 3. Solution: in Main(), put b.start() after ThreadGroup.add() x 3
In general, "a".equals(command) is better practice than command.equals("a") - it handles nulls, giving correct result without NPE (you seem lucky here - probably won't have nulls).
Suggested Changes:
public class ThreadA extends Thread {
ThreadC threadC;
public void setThreadC(ThreadC threadC) {
this.threadC = threadC;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
Random generator = new Random();
int i, j;
do {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
i=generator.nextInt(100)+1;
j=generator.nextInt(100)+1;
} while (i != j);
threadC.start();
}
}
public class ThreadB extends Thread {
ThreadA threadA;
ThreadC threadC;
public void setThreadA(ThreadA threadA) {
this.threadA = threadA;
}
public void setThreadC(ThreadC threadC) {
this.threadC = threadC;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
// loop until interrupted
try {
while (!this.isInterrupted()) {
command = reader.readLine();
if ("a".equals(command)) {
System.out.println("a was entered");
if (threadA.getState() == Thread.State.NEW) {
threadA.start();
}
} else if ("b".equals(command)) {
System.out.println("b was entered");
} else if ("c".equals(command)) {
System.out.println("c was entered");
} else if ("z".equals(command)) {
System.out.println("z was entered");
throw new InterruptedException("Command z interruption");
} else {
System.out.println("no such command");
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
}
// Now notify ThreadC - it will wait() until this code is run
synchronized(threadC) {
threadC.notify();
}
}
}
public class ThreadC extends Thread {
ThreadB threadB;
public void setThreadB(ThreadB threadB) {
this.threadB = threadB;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
// Block until the lock can be obtained
// We want thread B to run first, so the lock should be passed into Thread C constructor in an already locked state
threadB.interrupt();
synchronized(this) {
try {
// Put this thread to sleep until threadB calls threadC.notify().
//
// Note: could replace this line with threadB.join() - and remove
// from threadB the call to threadC.notify()
this.wait();
} catch (InterruptedException ie) {
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
while (!"e".equals(command)) {
try {
command= reader.readLine();
if ("d".equals(command)) {
System.out.println("d was entered");
} else if ("e".equals(command)) {
System.out.println("e was entered");
} else if ("f".equals(command)) {
System.out.println("f was entered");
} else if ("z".equals("command")) {
System.out.println("z was entered");
} else {
System.out.println("no such command");
};
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
}
nextLine() does not respond to interruption. You want to do something like
String command;
if (scanIn.hasNextLine())
command = scanIn.nextLine();
else
Thread.sleep(1000);
You can use flag variables (as global variables) to control the while loop in each thread...
suppose that Thread A has an infinite loop like this
while(true)
while(x == 1){
your code ...
}
Thread.sleep(2000);
}
when Thread b is started you can change x to 0 (suppose x is a global variable) then when Thread b finishes executing change x to 1 at the end of Thread b code...
or you can interrupt the thread from thread itself based of flag value x