Thread.sleep() stopping all threads - java

As per my understanding if there are multiple threads executing in parallel, Thread.sleep() will only sleep the thread in which it is called. However in my case Thread.sleep is making other threads sleep/wait. Is this expected behavior or am i doing something incorrect.
Find below my code
package stackoverflow;
public class SO {
public static void main(String[] args){
CallMe callMe = new CallMe();
Producer producer = new Producer(callMe);
Consumer consumer = new Consumer(callMe);
producer.thread.start();
consumer.thread.start();
}
}
class CallMe{
int a;
synchronized public int get(){
System.out.println("Get "+a);
return a;
}
synchronized public void put(int a){
System.out.println("Put "+a);
this.a=a;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Producer implements Runnable{
Thread thread;
CallMe callMe;
Producer(CallMe callMe){
thread=new Thread(this);
this.callMe=callMe;
}
public void run(){
int i=0;
while(true){
callMe.put(i);
i++;
}
}
}
class Consumer implements Runnable{
Thread thread;
CallMe callMe;
Consumer(CallMe callMe){
thread = new Thread(this);
this.callMe=callMe;
}
public void run(){
while (true) {
callMe.get();
}
}
}
While the put thread is put to sleep, the get should keep printing the output right? I am not giving any priority to any of the threads so if one thread is sleeping other should start executing. Isn't it?
I tried giving large value of sleep (100000000 millis) still console only shows Put 0 not printing Get <X> at all.

You have synchronized on both methods of your CallMe class. There is only one lock on which to synchronize for each object of that class. And you produce a singleton of that class. So one object with one lock being called via either of two methods across two threads.
Within one of these methods you sleep. During that sleep, you are holding the lock. The consumer thread calls the get method while the producer is holding the lock. The get method blocks, waiting for the lock, stopping the thread of the consumer. Eventually the producer thread wakes, releases the lock. The consumer thread grabs the lock, and proceeds.
This behavior is shown on the tutorial by Oracle.
Be sure to study the classic book by Brian Goetz, et al., Java Concurrency in Practice.
You have another issue as well.
You are sharing a resource, the int member field of CallMe, across two threads. Your code there is subject to visibility problems per the Java Memory Model. Because of modern CPU architecture, two threads accessing the same primitive value or object reference may see two different cached values. One solution is use of volatile keyword. I prefer the alternative, using the Atomic… classes.
I would replace that that with a final member field of type AtomicInteger.
Using AtomicInteger would also allow you to eliminate the synchronized tags, thereby eliminating your frozen-thread bottleneck.
So, killing two birds with one stone, we solve both your contention problem and your visibility problem by using AtomicInteger.
I suggest you learn about using executor service rather than addressing the Thread class directly.
To run a task repeatedly, use a scheduled executor service rather than sleeping.
Putting all that advice together, we might get code that looks like this.
package work.basil.example.prodcon;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;
public class CountManager
{
final AtomicInteger counter;
// Constructor
public CountManager ( )
{
this.counter = new AtomicInteger();
System.out.println( "CountManager constructor initialized the count to = " + this.counter.get() + " at " + Instant.now() );
}
public int getCount ( )
{
return this.counter.get();
}
public int increment ( )
{
return this.counter.incrementAndGet();
}
}
package work.basil.example.prodcon;
import java.time.Instant;
public class Producer implements Runnable
{
final private CountManager countManager;
public Producer ( CountManager countManager )
{
this.countManager = countManager;
}
#Override
public void run ( )
{
int newCount = this.countManager.increment();
System.out.println( "The producer in thread # " + Thread.currentThread().getId()+ " incremented newCount = " + newCount + " at " + Instant.now() );
}
}
package work.basil.example.prodcon;
import java.time.Instant;
public class Consumer implements Runnable
{
final private CountManager countManager;
public Consumer ( CountManager countManager )
{
this.countManager = countManager;
}
#Override
public void run ( )
{
int currentCount = countManager.getCount();
System.out.println( "The consumer on thread # " + Thread.currentThread().getId() + " reports currentCount = " + currentCount + " at " + Instant.now() );
}
}
Run that code in an app.
package work.basil.example.prodcon;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
System.out.println( "The app began demo on thread # " + Thread.currentThread().getId() + " at " + Instant.now() );
// Setup.
CountManager countManager = new CountManager();
Producer producer = new Producer( countManager );
Consumer consumer = new Consumer( countManager );
// Schedule some work to be done on background threads.
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate( producer , 0 , 7 , TimeUnit.SECONDS );
ses.scheduleAtFixedRate( consumer , 0 , 3 , TimeUnit.SECONDS );
// Let the app run a while.
try { Thread.sleep( Duration.ofMinutes( 1 ).toMillis() ); } catch ( InterruptedException e ) {e.printStackTrace(); }
ses.shutdown();
System.out.println( "The app ended demo on thread # " + Thread.currentThread().getId() + " at " + Instant.now() );
}
}
When run:
The app began demo on thread # 1 at 2021-02-14T02:10:09.981741Z
CountManager constructor initialized the count to = 0 at 2021-02-14T02:10:10.003056Z
The producer in thread # 14 incremented newCount = 1 at 2021-02-14T02:10:10.014164Z
The consumer on thread # 14 reports currentCount = 1 at 2021-02-14T02:10:10.026975Z
The consumer on thread # 14 reports currentCount = 1 at 2021-02-14T02:10:13.019270Z
The consumer on thread # 14 reports currentCount = 1 at 2021-02-14T02:10:16.016694Z
The producer in thread # 14 incremented newCount = 2 at 2021-02-14T02:10:17.016730Z
The consumer on thread # 14 reports currentCount = 2 at 2021-02-14T02:10:19.017666Z
The consumer on thread # 14 reports currentCount = 2 at 2021-02-14T02:10:22.017923Z
The producer in thread # 14 incremented newCount = 3 at 2021-02-14T02:10:24.015972Z
The consumer on thread # 14 reports currentCount = 3 at 2021-02-14T02:10:25.018212Z
The consumer on thread # 14 reports currentCount = 3 at 2021-02-14T02:10:28.048834Z
The producer in thread # 14 incremented newCount = 4 at 2021-02-14T02:10:31.016746Z
The consumer on thread # 14 reports currentCount = 4 at 2021-02-14T02:10:31.016944Z
The consumer on thread # 14 reports currentCount = 4 at 2021-02-14T02:10:34.016674Z
The consumer on thread # 14 reports currentCount = 4 at 2021-02-14T02:10:37.017195Z
The producer in thread # 14 incremented newCount = 5 at 2021-02-14T02:10:38.016650Z
The consumer on thread # 14 reports currentCount = 5 at 2021-02-14T02:10:40.017862Z
The consumer on thread # 14 reports currentCount = 5 at 2021-02-14T02:10:43.016564Z
The producer in thread # 14 incremented newCount = 6 at 2021-02-14T02:10:45.017760Z
The consumer on thread # 14 reports currentCount = 6 at 2021-02-14T02:10:46.016909Z
The consumer on thread # 14 reports currentCount = 6 at 2021-02-14T02:10:49.014339Z
The producer in thread # 14 incremented newCount = 7 at 2021-02-14T02:10:52.013271Z
The consumer on thread # 14 reports currentCount = 7 at 2021-02-14T02:10:52.013389Z
The consumer on thread # 14 reports currentCount = 7 at 2021-02-14T02:10:55.017526Z
The consumer on thread # 14 reports currentCount = 7 at 2021-02-14T02:10:58.017050Z
The producer in thread # 14 incremented newCount = 8 at 2021-02-14T02:10:59.014334Z
The consumer on thread # 14 reports currentCount = 8 at 2021-02-14T02:11:01.013358Z
The consumer on thread # 14 reports currentCount = 8 at 2021-02-14T02:11:04.014889Z
The producer in thread # 14 incremented newCount = 9 at 2021-02-14T02:11:06.015598Z
The consumer on thread # 14 reports currentCount = 9 at 2021-02-14T02:11:07.014802Z
The consumer on thread # 14 reports currentCount = 9 at 2021-02-14T02:11:10.017313Z
The app ended demo on thread # 1 at 2021-02-14T02:11:10.017975Z

Related

Flux stream after .map() function not in order

while trying to get familiar with Flux I want to have a stream of Data within a Flux.
the .map() function should simulate a workload which requires some random processing time per Magician object and is happening in separate Threads (as you can see in the output at Thread id to make use of Multi-Threading.
Finally the stream should return the results in order. But no matter what I do, e.g. using .sequential(), or where it always ends up in in being unordered.
Can someone tell me how I can make use of Multi-Threading (using .map() or any other sequence as long as the result is the one asked) and having the results in order please? Thank you
P.S. The business logic behind this question is that I am calling an Endpoint that delivers a Flux<byte[]>
These bytes I need to process in parallel (decryption) and therefor forward in order to another consumer.
public class FluxRunner {
public void getWorkerStream() throws InterruptedException {
final int[] counter = new int[1];
// create workers
final Flux<Magician[]> workersFlux = Flux.range(0, 10)
.map(integer -> {
final Magician[] worker = new Magician[1];
worker[0] = new Magician(counter[0], counter[0]++);
return worker;
});
final Disposable disposable = workersFlux
.parallel()
.runOn(Schedulers.parallel())
.map(workers -> {
System.out.println("Thread id: " + Thread.currentThread().getId());
workers[0].calculate();
return workers;
})
.sequential() // no effect, doOnNext is unordered
.doOnNext(workers -> System.out.println(workers[0].getId()))
.subscribe();
while (!disposable.isDisposed()) {
sleep(500);
}
}
}
#Data
class Magician {
final int id;
int number;
Magician(final int id, final int number) {
this.id = id;
this.number = number;
}
public void calculate() {
int timeToSleep = (int) (Math.random() * 3000);
System.out.println("Sleep for " + timeToSleep + " seconds");
try {
sleep(timeToSleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
number++;
}
}
result will be
Thread id: 33
Thread id: 24
Thread id: 25
Thread id: 31
Thread id: 29
Thread id: 30
Thread id: 27
Thread id: 32
Thread id: 28
Thread id: 26
Sleep for 2861 seconds
Sleep for 2811 seconds
Sleep for 711 seconds
Sleep for 2462 seconds
Sleep for 1858 seconds
Sleep for 601 seconds
Sleep for 126 seconds
Sleep for 359 seconds
Sleep for 2014 seconds
Sleep for 2356 seconds
4
5
7
9
8
3
0
1
6
2
You can use flatMapSequential operator along with .subscribeOn(Schedulers.parallel()) to get the desired result:
final Disposable disposable = workersFlux
.flatMapSequential(workers -> Mono.fromCallable(() -> {
System.out.println("Thread id: " + Thread.currentThread().getId());
workers[0].calculate();
return workers;
}).subscribeOn(Schedulers.parallel()))
.doOnNext(workers -> System.out.println(workers[0].getId()))
.subscribe();

AtomicInteger a1 increase before a2, and decrease after a2, why exists a2 > a1

there is the code:
AtomicInteger a1 = new AtomicInteger();
AtomicInteger a2 = new AtomicInteger();
for (int i = 0; i < 100; i++) {
new Thread(()->{
for (int j = 0; j < 1e4; j++) {
a1.incrementAndGet();
a2.incrementAndGet();
int v2 = a2.decrementAndGet();
if(v2>a1.get()){
System.out.println("error a2 > a1");
}
a1.decrementAndGet();
}
}).start();
}
why exists println error a2 > a1?
thanks!
action
a1
a2
a1+
1
0
a2+
1
1
a2-
1
0
a1-
0
0
use redhat windows openjdk-1.8.0.222
Imagine this scenario:
All 100 threads complete the increments and the last thread now has a1 = 100, a2 = 100.
Now the first thread to calculate v2 will get v2 = 99.
If the other 99 threads finish and decrement before that one thread goes any further, it will then be checking 99 > 1 and be true.
Short answer: Other threads can decrement a1 between int v2 = a2.decrementAndGet() and if(v2>a1.get())
The Answer by jdkramhoft is correct. You have two resources (the pair of AtomicInteger objects) being manipulated across threads that are not protected. Each individual call to increment, decrement, and get on each AtomicInteger happens atomically. But multiple calls across threads may be interleaved, not atomic, not thread-safe.
To make the group of increment, decrement, and get calls atomic, you must guard them as a group. One easy way to do that is to use synchronized. In the code below we arbitrarily chose our AtomicInteger named a1 to be the lock object for our synchronized call.
By synchronizing the code block on the same object (a1), we guarantee that only one thread at a time may be running that code block. When the other thread gets to the point of trying to run that block, it must wait for the synchronized lock to be freed.
The use of 1e4 is a bit precious, so let's use 10_000 instead. Even 1_000 is enough for our purposes here, and is less likely to blow out our console buffer.
I am no expert on concurrency, but the following code seems thread-safe to me. Perhaps others can point out any flaws. At any rate, use at your own risk.
package work.basil.demo.threads;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;
public class App
{
public static void main ( String[] args )
{
System.out.println( "INFO - Starting the main method of our demo. " + Instant.now() );
AtomicInteger a1 = new AtomicInteger();
AtomicInteger a2 = new AtomicInteger();
for ( int i = 0 ; i < 100 ; i++ )
{
System.out.println( "Instantiating thread # " + i + " | " + Instant.now() );
new Thread( ( ) -> {
for ( int j = 0 ; j < 1_000 ; j++ )
{
synchronized ( a1 )
{
a1.incrementAndGet();
a2.incrementAndGet();
int v2 = a2.decrementAndGet();
if ( v2 > a1.get() )
{
System.out.println( "error a2 > a1" );
}
a1.decrementAndGet();
}
System.out.println( "Finishing thread id " + Thread.currentThread().getId() + " | " + Instant.now() );
}
} ).start();
}
try { Thread.sleep( Duration.ofSeconds( 10 ).toMillis() ); } catch ( InterruptedException e ) { e.printStackTrace(); }
System.out.println( "a1 = " + a1.get() );
System.out.println( "a2 = " + a2.get() );
}
}
When run.
INFO - Starting the main method of our demo. 2021-06-06T00:05:12.869874Z
Instantiating thread # 0 | 2021-06-06T00:05:12.875289Z
Instantiating thread # 1 | 2021-06-06T00:05:12.887569Z
Instantiating thread # 2 | 2021-06-06T00:05:12.888805Z
Instantiating thread # 3 | 2021-06-06T00:05:12.891298Z
Finishing thread id 16 | 2021-06-06T00:05:12.891789Z
Finishing thread id 16 | 2021-06-06T00:05:12.894783Z
…
Finishing thread id 57 | 2021-06-06T00:05:13.634241Z
Finishing thread id 57 | 2021-06-06T00:05:13.634245Z
Finishing thread id 57 | 2021-06-06T00:05:13.634247Z
a1 = 0
a2 = 0
By the way, a quick mention: In modern Java, we rarely need to address the Thread class directly. Better to use the Executors framework added to Java 5. Submit your tasks as Runnable/Callable object to be run on background threads.

Multithreading using synchronized

I am learning multithreading. I have a following code:
public class Intro {
public static void main(String[] args) {
new Intro().doCounter();
}
private int counter = 0;
synchronized void increment() {
counter++;
}
private void doCounter() {
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 1_000_000; i++) {
increment();
}
System.out.println("first: " + counter);
}
});
Thread thread2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 1_000_000; i++) {
increment();
}
System.out.println("second: " + counter);
}
});
thread1.start();
thread2.start();
}
}
Output (can differ):
first: 1741739
second: 2000000
The code has two threads. One thread increment the counter million times, while the second wait. Then the second increment it million times as well. I understand why the second thread get 2 million, but didn't get why the first thread get 1741739. Why it isn't 1 million for the first thread? I think it had to stop at 1 million. Thanks for explanation.
As discussed in the comments, you have two problems.
You need to understand that threading execution is not predictable. Each thread gets scheduled for a certain amount of time on a CPU core as decided by the JVM and the OS. How often each thread gets scheduled, and for how long, depends on conditions at runtime. So their work can be interleaved, with no guarantee as to which thread will run when, or finish first/last.
Your code is accessing a resource, a member field variable counter across threads without protection. This is not thread-safe. Due to modern CPU architecture and the Java Memory Model, your two threads might see two different states of that single variable. For example, each of two cores running your two threads might each have a different copy of the variable in its cache.
One solution is to use AtomicInteger as your counter variable rather than int. An AtomicInteger is thread-safe, protecting access to its contained int value. By using AtomicInteger, you no longer need your synchronized increment method.
Here is some example code for that.
An Incrementor class that contains our AtomicInteger variable named count as a member field. The class carries nested class IncrementingTask that is a Runnable with a run method to be executed on background threads, incrementing our count var a million times. The class has a demo method for starting any number of threads, each thread running an instance of IncrementingTask to increment the million times.
package work.basil.threading;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class Incrementor
{
// Member fields.
final private AtomicInteger count = new AtomicInteger( 0 );
public void demo ( )
{
int threadsLimit = 2;
ExecutorService executorService = Executors.newFixedThreadPool( threadsLimit );
for ( int i = 0 ; i < threadsLimit ; i++ )
{
executorService.submit( new IncrementingTask() );
}
executorService.shutdown();
try { executorService.awaitTermination( 1 , TimeUnit.HOURS ); } catch ( InterruptedException e ) { e.printStackTrace(); }
// At this point, the tasks are all done/canceled/failed.
System.out.println( "RESULTS: count is at: " + this.count.get() );
}
// Runnable task.
class IncrementingTask implements Runnable
{
#Override
public void run ( )
{
for ( int i = 0 ; i < 1_000_000 ; i++ )
{
int incrementedCount = count.incrementAndGet();
if ( i % 100_000 == 0 )
{
System.out.println( "Thread # " + Thread.currentThread().getId() + " incremented count to: " + incrementedCount + " at " + Instant.now() );
}
}
System.out.println( "Thread # " + Thread.currentThread().getId() + " is done incrementing. " + Instant.now() );
}
}
}
A class to run this.
package work.basil.threading;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
Incrementor incrementor = new Incrementor();
incrementor.demo();
}
}
When run.
Thread # 15 incremented count to: 2 at 2021-03-29T00:04:37.099350Z
Thread # 14 incremented count to: 1 at 2021-03-29T00:04:37.099281Z
Thread # 14 incremented count to: 200002 at 2021-03-29T00:04:37.155680Z
Thread # 15 incremented count to: 198267 at 2021-03-29T00:04:37.155659Z
Thread # 15 incremented count to: 387108 at 2021-03-29T00:04:37.165850Z
Thread # 14 incremented count to: 400002 at 2021-03-29T00:04:37.165894Z
Thread # 15 incremented count to: 552150 at 2021-03-29T00:04:37.168378Z
Thread # 14 incremented count to: 631000 at 2021-03-29T00:04:37.169329Z
Thread # 15 incremented count to: 753457 at 2021-03-29T00:04:37.170931Z
Thread # 14 incremented count to: 840455 at 2021-03-29T00:04:37.171943Z
Thread # 15 incremented count to: 942263 at 2021-03-29T00:04:37.173276Z
Thread # 14 incremented count to: 1049089 at 2021-03-29T00:04:37.174559Z
Thread # 15 incremented count to: 1135900 at 2021-03-29T00:04:37.175726Z
Thread # 14 incremented count to: 1240800 at 2021-03-29T00:04:37.177092Z
Thread # 15 incremented count to: 1308191 at 2021-03-29T00:04:37.177678Z
Thread # 15 incremented count to: 1439696 at 2021-03-29T00:04:37.179523Z
Thread # 15 incremented count to: 1595283 at 2021-03-29T00:04:37.180795Z
Thread # 14 incremented count to: 1604140 at 2021-03-29T00:04:37.181720Z
Thread # 14 incremented count to: 1800001 at 2021-03-29T00:04:37.183231Z
Thread # 14 incremented count to: 1900001 at 2021-03-29T00:04:37.184697Z
Thread # 15 is done incrementing. 2021-03-29T00:04:37.182735Z
Thread # 14 is done incrementing. 2021-03-29T00:04:37.188265Z
RESULTS: count is at: 2000000
Notice that every time we run this, we always get to exactly 2,000,000 million total. Also notice that every time you run this, the list of which thread ran when will vary, as will the count at each time the thread reports to us on the console.
Console lies
Notice the counts look crazy. The first two lines report a count of 2 and then 1 rather than one then two. Same with the third and fourth lines, apparently backwards.
Look more closely to examine the microseconds of the timestamps. Those timestamps are not in chronological order.
Lesson learned: The System.out.println calls do not present on the console in chronological order. So never rely on such console output to give you a true picture of what happened when.
Always include a timestamp such as Instant.now() or System.nanoTime(). If you want to see messages in order, collect them in a thread-safe ordered collection such as Collections.synchronizedList​( new ArrayList< String >() ).
Alternatively, if you wanted to keep your int variable and synchronized increment method rather than use AtomicInteger you must protect access to the counter variable in a thread-safe manner. Marking the variable as volatile would help. You can search Stack Overflow to learn more on this.

What is the real time benefits of creating Thread in Java?

class ThreadDemo extends Thread
{
public void run()
{
for(int i =0; i<5;i++)
{
System.out.println(i);
}
}
}
class ThreadApp
{
public static void main(String args[])
{
ThreadDemo thread1 = new ThreadDemo();
thread1.start();
ThreadDemo thread2 = new ThreadDemo();
thread2.start();
ThreadDemo thread3 = new ThreadDemo();
thread3.start();
}
}
Output:
0
2
3
1
4
1
2
4
3
0
0
1
2
3
4
By default, Java applications are single thread application. We are going for the concept called multithreading to share the work. Means, instead of doing the work with one thread (Main thread) if we create the thread, then it will simplifies the work. I understood this thing theoretically. My doubt arises when I start coding.
In the above program I have created 3 threads. If 3 threads are working on the same logic (iteration and printing the values by using for loop) why it is giving 3 separate output instead of giving one set of values from 0 to 4?
Duplicating the work, not sharing the work
You said:
We are going for the concept called multithreading to share the work.
But you did not share the work. You repeated the work. Instead of running a for loop once, you ran a for loop three times, once in each of three threads.
You asked:
why it is giving 3 separate output instead of giving one set of values from 0 to 4?
If a school teacher asks each of three pupils to write the alphabet on the board, we would end up not with 26 letters but with 78 letters (3 * 26). Each pupil would be looping through the letters of the alphabet. Likewise, each of your three threads looped through the count of zero to four.
Your for loop is local to (within) your task code. So each thread runs all of that code starting at the top. So the for loop executes three times, one per thread.
Beware: System.out prints out-of-order
Sending text to System.out via calls to println or print does not result in text appearing immediately and in the order sent. The lines of text you send may appear out of order.
When examining a sequence of statements, always include a timestamp such as java.time.Instant.now(). Then study the output. You may need to manually re-order the outputs using a text editor to see the true sequence.
You can see the out-of-chronological-order lines in my own example output below.
Executor service
In modern Java we no longer need address the Thread class directly. Generally best to use the Executors framework. See Oracle Tutorial.
package work.basil.example;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Counter
{
public static void main ( String[] args )
{
ExecutorService executorService = Executors.newCachedThreadPool();
Runnable task = new Runnable()
{
#Override
public void run ( )
{
for ( int i = 0 ; i < 5 ; i++ )
{
System.out.println( "i = " + i + " at " + Instant.now() + " on thread " + Thread.currentThread().getName() );
}
}
};
executorService.submit( task );
executorService.submit( task );
executorService.submit( task );
// Let our program run a while, then gracefully shutdown the executor service.
// Otherwise the backing thread pool may run indefinitely, like a zombie 🧟‍.
try { Thread.sleep( Duration.ofSeconds( 5 ).toMillis() ); }catch ( InterruptedException e ) { e.printStackTrace(); }
executorService.shutdown();
try { executorService.awaitTermination( 1 , TimeUnit.MINUTES ); } catch ( InterruptedException e ) { e.printStackTrace(); }
}
}
When run.
i = 0 at 2021-01-06T05:28:34.349290Z on thread pool-1-thread-1
i = 1 at 2021-01-06T05:28:34.391997Z on thread pool-1-thread-1
i = 0 at 2021-01-06T05:28:34.349246Z on thread pool-1-thread-2
i = 0 at 2021-01-06T05:28:34.349464Z on thread pool-1-thread-3
i = 1 at 2021-01-06T05:28:34.392467Z on thread pool-1-thread-3
i = 2 at 2021-01-06T05:28:34.392162Z on thread pool-1-thread-1
i = 2 at 2021-01-06T05:28:34.392578Z on thread pool-1-thread-3
i = 3 at 2021-01-06T05:28:34.392670Z on thread pool-1-thread-1
i = 3 at 2021-01-06T05:28:34.392773Z on thread pool-1-thread-3
i = 4 at 2021-01-06T05:28:34.393165Z on thread pool-1-thread-3
i = 1 at 2021-01-06T05:28:34.392734Z on thread pool-1-thread-2
i = 4 at 2021-01-06T05:28:34.392971Z on thread pool-1-thread-1
i = 2 at 2021-01-06T05:28:34.395138Z on thread pool-1-thread-2
i = 3 at 2021-01-06T05:28:34.396407Z on thread pool-1-thread-2
i = 4 at 2021-01-06T05:28:34.397002Z on thread pool-1-thread-2
Project Loom
Project Loom promises to be bring to Java new features such as virtual threads (fibers), and making ExecutorService be AutoCloseable for use with try-with-resources to automatically shutdown.
Let's rewrite the above code to use Project Loom technologies. Preliminary builds are available now based on early-access Java 16.
Also, we can rewrite the anonymous class seen above with simpler lambda syntax.
Another difference from above: Virtual threads do not have a name. So we switch to using the id number of the thread to differentiate between threads running.
try
(
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
)
{
Runnable task = ( ) -> {
for ( int i = 0 ; i < 5 ; i++ )
{
System.out.println( "i = " + i + " at " + Instant.now() + " on thread " + Thread.currentThread().getId() );
}
};
executorService.submit( task );
executorService.submit( task );
executorService.submit( task );
}
// At this point, the flow-of-control blocks until all submitted tasks are done.
// And the executor service is also shutdown by this point.
When run.
i = 0 at 2021-01-06T05:41:36.628800Z on thread 17
i = 1 at 2021-01-06T05:41:36.647428Z on thread 17
i = 2 at 2021-01-06T05:41:36.647626Z on thread 17
i = 3 at 2021-01-06T05:41:36.647828Z on thread 17
i = 4 at 2021-01-06T05:41:36.647902Z on thread 17
i = 0 at 2021-01-06T05:41:36.628842Z on thread 14
i = 1 at 2021-01-06T05:41:36.648148Z on thread 14
i = 2 at 2021-01-06T05:41:36.648227Z on thread 14
i = 3 at 2021-01-06T05:41:36.648294Z on thread 14
i = 4 at 2021-01-06T05:41:36.648365Z on thread 14
i = 0 at 2021-01-06T05:41:36.628837Z on thread 16
i = 1 at 2021-01-06T05:41:36.648839Z on thread 16
i = 2 at 2021-01-06T05:41:36.648919Z on thread 16
i = 3 at 2021-01-06T05:41:36.648991Z on thread 16
i = 4 at 2021-01-06T05:41:36.649054Z on thread 16
Sharing state across threads
If you really wanted to share values across the threads, you define them outside the immediate task code.
In this next example, we define a class Counter that implements Runnable. As a Runnable we can pass an instance of this class to an executor service. We defined a member field, a ConcurrentMap (a thread-safe Map) that tracks each of our desired numbers 0-4. For each of those five numbers, we map to the id number of the virtual thread that was able to beat the other virtual threads to submitting that entry into our originally-empty map.
Be aware that we are submitting a single Counter object to all three threads. So all three threads have access to the very same ConcurrentMap object. That is why we must use a ConcurrentMap rather than a plain Map. Any resource shared across threads must be built to be thread-safe.
We are calling Thread.sleep to try to mix things up. Otherwise, the first thread might finish all the work while the main thread is still submitting to the second and third threads.
package work.basil.example;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
public class Counter implements Runnable
{
public ConcurrentMap < Integer, Long > results = new ConcurrentHashMap <>();
#Override
public void run ( )
{
try { Thread.sleep( Duration.ofMillis( 100 ) ); } catch ( InterruptedException e ) { e.printStackTrace(); }
Long threadId = Thread.currentThread().getId(); // ID of this thread.
for ( int i = 0 ; i < 5 ; i++ )
{
// Shake things up by waiting some random time.
try { Thread.sleep( Duration.ofMillis( ThreadLocalRandom.current().nextInt(1, 100) ) ); } catch ( InterruptedException e ) { e.printStackTrace(); }
results.putIfAbsent( i , threadId ); // Auto-boxing converts the `int` value of `i` to be wrapped as a `Integer` object.
}
}
}
Here is a main method to make our exercise happen.
public static void main ( String[] args )
{
Counter counter = new Counter();
try
(
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
)
{
executorService.submit( counter );
executorService.submit( counter );
executorService.submit( counter );
}
// At this point, the flow-of-control blocks until all submitted tasks are done.
// And the executor service is also shutdown by this point.
System.out.println( "counter.results = " + counter.results );
}
In the results of this particular run, we can see that the two threads number 16 and 17 had all the success in putting entries into our map. The third thread was not able to be the first to put in any of the five entries.
counter.results = {0=16, 1=17, 2=17, 3=16, 4=16}
Try to do some various tests and see by yourself what is coming and from where
public class ThreadApp {
public static void main(String args[]) throws InterruptedException {
ThreadDemo thread1 = new ThreadApp().new ThreadDemo("t1",4);
ThreadDemo thread2 = new ThreadApp().new ThreadDemo("t2",7);
thread2.start();
thread1.start();
ThreadDemo thread3 = new ThreadApp().new ThreadDemo("t3",2);
// wait till t1 &t2 finish run then launch t3
thread1.join();
thread2.join();
thread3.start();
}
class ThreadDemo extends Thread {
int stop;
public ThreadDemo(String name, int stop) {
super(name);
this.stop = stop;
}
public void run() {
for (int i = 0; i < stop; i++) {
System.out.println(this.getName() + ":" + i);
}
}
}
}
Possible Output:
t2:0
t2:1
t1:0
t2:2
t1:1
t2:3
t1:2
t2:4
t1:3
t2:5
t2:6
//due to join t3 start only after t1 & t2 finish their run
t3:0
t3:1
Related to benefits, just one hint Producer-Consumer problem ...

Why does SwingWorker stop unexpectedly?

I wanted to try out some ideas using SwingWorker since I haven't used it too much. Instead, I ran into an issue and I can't figure out what's wrong.
Here's a short SSCCE that demonstrates this problem (I know people here like SSCCEs):
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class SwingWorkerTest
{
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
#Override
public void run ()
{
new MySwingWorker (500).execute ();
new MySwingWorker (900).execute ();
new MySwingWorker (1200).execute ();
}
});
}
}
class MySwingWorker extends SwingWorker<Void, Void>
{
private int ms;
public MySwingWorker (int ms)
{
this.ms = ms;
}
#Override
protected Void doInBackground()
{
Thread t = Thread.currentThread ();
for (int i = 0; i < 50; i++)
{
try
{
Thread.sleep (ms);
}
catch (InterruptedException e)
{
e.printStackTrace ();
}
System.out.println ("I am thread with " + ms + " sleep in iteration " + i + ": " + t.getName () + " (" + t.getId () + ")");
}
return null;
}
}
So my program should create 3 SwingWorkers that print a line on the screen then sleep for the specified number of milliseconds and then print the line again and sleep again etc. I create the SwingWorkers from within Swing's thread because otherwise they wouldn't even start.
So the expected output is:
I am thread with 500 sleep in iteration 0: SwingWorker-pool-1-thread-1 (15)
I am thread with 900 sleep in iteration 0: SwingWorker-pool-1-thread-2 (16)
I am thread with 500 sleep in iteration 1: SwingWorker-pool-1-thread-1 (15)
I am thread with 1200 sleep in iteration 0: SwingWorker-pool-1-thread-3 (17)
I am thread with 500 sleep in iteration 2: SwingWorker-pool-1-thread-1 (15)
I am thread with 900 sleep in iteration 1: SwingWorker-pool-1-thread-2 (16)
I am thread with 500 sleep in iteration 3: SwingWorker-pool-1-thread-1 (15)
I am thread with 1200 sleep in iteration 1: SwingWorker-pool-1-thread-3 (17)
I am thread with 500 sleep in iteration 4: SwingWorker-pool-1-thread-1 (15)
I am thread with 900 sleep in iteration 2: SwingWorker-pool-1-thread-2 (16)
I am thread with 500 sleep in iteration 5: SwingWorker-pool-1-thread-1 (15)
I am thread with 500 sleep in iteration 6: SwingWorker-pool-1-thread-1 (15)
I am thread with 900 sleep in iteration 3: SwingWorker-pool-1-thread-2 (16)
I am thread with 1200 sleep in iteration 2: SwingWorker-pool-1-thread-3 (17)
I am thread with 500 sleep in iteration 7: SwingWorker-pool-1-thread-1 (15)
.............
and so on for a total of 150 lines (3 workers x 50 iterations for each)
Instead, the output I get is:
I am thread with 500 sleep in iteration 0: SwingWorker-pool-1-thread-1 (15)
I am thread with 900 sleep in iteration 0: SwingWorker-pool-1-thread-2 (16)
I am thread with 500 sleep in iteration 1: SwingWorker-pool-1-thread-1 (15)
And that's it. Just 3 lines. After this the program exits. There's no stacktrace anywhere from that try catch block.
1). Where is the worker with the 1200ms sleep ? Actually, if I replace 1200ms with 1000ms, then this worker also prints 1 line... yes, only one. Weird...
2). Why do the workers stop ? (and I don't get 150 lines of stuff)
I ran this program using JRE 7 Update 11 on Windows 7 64-bit.
PS: I'm pretty sure that the bug mentioned here was fixed in this version of JRE, since I do get 2 distinct values (15 and 16) as thread ID's printed on the console. This was the first thing I suspected.
I believe that you need to show a visualized Swing top level Window in order to keep the Swing event thread alive. Otherwise the program will shut down for lack of non-daemon threads.
Edit:
To prove that the SwingWorker thread is a Daemon thread, just add a line of code to test it:
System.out.println("I am thread with " + ms + " sleep in iteration "
+ i + ": " + t.getName() + " (" + t.getId() + ")");
// **** added
System.out.println("Daemon?: " + Thread.currentThread().isDaemon());
If you look at line 771 of SwingWorker class source code (Java SE 7):
thread.setDaemon(true);
You will see that the SwingWorker is executed within a daemon thread, and in Java the JVM will be terminated if all non-daemon threads are finished.
As already mentioned, you can use the UI to keep the threads alive.
Alternatively, what you can do is use SwingWorker#get (or anything that prevents the main thread from terminating) to wait for the threads to finish. By doing so, you will get the output as expected. Here is the modified code, that does what you want.
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.util.concurrent.ExecutionException;
public class SwingWorkerTest
{
public static void main (String[] args)
{
final MySwingWorker w1 = new MySwingWorker (500),
w2 = new MySwingWorker (900),
w3 = new MySwingWorker (1200);
SwingUtilities.invokeLater (new Runnable ()
{
#Override
public void run ()
{
w1.execute ();
w2.execute ();
w3.execute ();
}
});
try{
// you can replace the code in this block
// by anything that keeps the program from
// terminating before the threads/SwingWorkers.
w1.get();
w2.get();
w3.get();
}catch(InterruptedException e){
System.err.println("InterruptedException occured");
}catch(ExecutionException e){
System.err.println("InterruptedException occured");
}
}
}
class MySwingWorker extends SwingWorker<Void, Void>
{
private int ms;
public MySwingWorker (int ms)
{
this.ms = ms;
}
#Override
protected Void doInBackground()
{
Thread t = Thread.currentThread ();
for (int i = 0; i < 50; i++)
{
try
{
Thread.sleep (ms);
}
catch (InterruptedException e)
{
e.printStackTrace ();
}
System.out.println ("I am thread with " + ms + " sleep in iteration " + i + ": " + t.getName () + " (" + t.getId () + ")");
}
return null;
}
}
Have you tried creating any UI? or putting something like new Object().wait(); at the end of main, to prevent the main thread from exiting?
I'm not entirely sure that this is the case, but without any actual UI showing, i'm pretty sure the swing workers are just another thread, and you haven't configured any as daemon threads, so main starts them up, main finishes, and the process exits?

Categories