Introduction
Read it offline(pdf).Sometimes you need to do some tasks together (simultaneously), for example copying a file and showing the progress, or playing a music while showing some pictures as slideshow, or a listener to handle cancel event for aborting a file copy operation. If a program needs to run (do) more than one task (thread) at a time, that kind of a program is called concurrent (multi-thread)program.
The main problem with parallel programs is synchronization between running threads, because each thread wants to finish its process ASAP.
Synchronizing threads is not such a complex or hard work, it could be done very easily. In some cases it may need a lot of code and might complicate the application flow, but I say again it's easy.
Table of Contents
- Why Concurrent Programs?
- Creating Threads
- Managing Threads
- Synchronizing Threads
- How to Synchronize Two Threads With Each Other?
- Synchronized Block
- Synchronized Methods
- volatile Keyword
- Notes
- Main Thread
- Creating Threads
- Daemon Threads
- Shutting Down a Thread
- wait(1000) vs. sleep(1000)
- Switching Between Threads (Untruthful yield())
- Advanced Topics
Why Concurrent Programs?
Let's answer this question with another question, why single-threaded programs? Sometimes some-tasks need to run together in a program, (specially in a graphical user interface) a game as an example, you have to track time, manage the objects, play the sounds at the same time, and this could be done in a multi-threaded manner. Even a simple program like calling an internet address (resource), user should be able to cancel the operation, and it could be done by two separated threads. In fact we have to separate a program into small units that would work concurrently, but sometimes it's impossible for some sort of applications (like a sequential math formula, or connecting to a database).
How to Convert a Single-thread Program to Parallel One? Is it possible?
It is impossible for programs that each step is completely dependent to the previous step, and usually does just one task overall, a timer program(without interruption) for instance.
We need to find tasks in an application that need to or would run with a separated thread, for example in a game, we have to render the frames, and play the related sounds concurrently, so we need threads. Or in a GUI program, we would run the file loading task as a thread to avoid freezing the GUI.
Generally...- If a program performs more than one task (usually GUI apps), so this is possible to run each task as a thread if and only if there are no tight step-by-step dependencies between tasks
- A task could be split to small units of works, if and only if there is no line-by-line(tight) dependencies in the tasks, for example initializing a big array
One of the reason to prefer a parallel program than single-thread one is to get the maximum power of the processor, either GPU or CPU, if a file conversion utilizes 10% of CPU, why don't we run 10 concurrent threads to utilize 100% of CPU and reduce the execution time ?!
Creating Threads
So first of all, we need to know how to create a thread. A thread is specified with a Runnable
interface or
a Thread
class in Java.
Here we use Java, but you could do it with any language, any library, you just need to know about the logic.
Java
In the Java language, as mentioned, either the Runnable
interface or the Thread
class is used for specifying a thread. The Thread
class starts
the thread, it accepts an implementation of Runnable
and starts the thread either in a separate thread or the current thread.
The Runnable
interface just has a void
method called Run
which does not accept any arguments, so for any input, you would pass it via
the class that has just implemented it.
Example
The following example is just about two threads that get started from the main thread (first thread).
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) {
Runnable r0,r1;//pointers to thread methods
r0=new FirstIteration(); //init Runnable
r1=new SecondIteration();
Thread t0,t1;//Thread class is used for starting a thread (runnable instance)
t0=new Thread(r0);//init thread object, but haven't started yet
t1=new Thread(r1);
t0.start();//start the thread simultaneously
t1.start();
System.out.print("Threads started, no surprise here!\n");
}
}
class FirstIteration implements Runnable{
@Override
public void run() {//thread starts from here
for(int i=0;i<20;i++){
System.out.print("Hello from 1st. thread, iteration="+i+"\n");
}
}
}
class SecondIteration implements Runnable{
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.print("who just called 2st. thread? iteration="+i+"\n");
}
}
}
Just try the above code many times and you will be faced with different responses, this is because threads have Race conditions, which means each thread wants to finish its job ASAP. The following diagram is showing what is happening in above example.
Exercises
And now, this is your turn, just stop using Ctrl+c and Ctrl+v, and try to do the following practices (feel free to contact for any issues).
- A program that creates 100 randomized name folders concurrently
Develop the above example in single thread manner too.
Passing argument(s) to threads
It's really easy to pass a value to a thread, but it is impossible with the
Runnable
implicitly, it could be done by host class, constructor, setters, etc...
Example
Check out the following example for a better understanding.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) {
Runnable r0,r1;//pointers to a thread method
r0=new FirstIteration("Danial"); //init Runnable, and pass arg to thread 1 by constructor
SecondIteration si=new SecondIteration();
si.setArg("Pedram");// pass arg to thread 2 by setter
r1=si;
Thread t0,t1;
t0=new Thread(r0);
t1=new Thread(r1);
t0.start();
t1.start();
System.out.print("Threads started with args, nothing more!\n");
}
}
class FirstIteration implements Runnable{
public FirstIteration(String arg){
//input arg for this class, but in fact input arg for this thread.
this.arg=arg;
}
private String arg;
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.print("Hello from 1st. thread, my name is "+
arg+"\n");//using the passed(arg) value
}
}
}
class SecondIteration implements Runnable{
public void setArg(String arg){//pass arg either by constructors or methods.
this.arg=arg;
}
String arg;
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.print("2)my arg is="+arg+", "+i+"\n");
}
}
}
In the above example we passed a String
value as an argument to threads, but remember that it should get passed by the hosted class (impl class).
Exercises
And now, here is your turn, try to do the following:
- An application which multiply two float arrays A, B and store the results in the array C (c[0]=a[0]*b[0])(Hint: pass the array references and index)
- A program that gets string line(s) from the user and saves them into 10 files
- A program that creates 100 folders named from 0 to 99 concurrently
- A program that kills every other OS process concurrently (Dangerous!, don't really try to do that)
Managing Threads
Well, we have just done about creating and running threads, but how do we manage them? How do we sleep (idle) a thread (stop for a particular time)? How do we pause (stop working till a resume signal) a thread? How do we shutdown a running thread? Or how do we get the current running thread?
Thread's Properties
Generally in every language and platform, threads have some common properties, for example, thread id or private memory(stack). So let's have a closer look.
Properties
- Thread id
- Thread name
- Thread State
- Runnable: indicates that the thread has started and is running.
- New: indicates the thread has been created, but hasn't invoked (started) yet-when you just create an instance of
the thread and haven't attempted to invoke the
start()
. - Blocked: when a thread is in running state and is blocked because it is waiting for locking a resource which has been locked by another thread.
- Waiting: when the thread is idle and is waiting for a signal (notify).
- Timed_Waiting: when the thread is sleeping for a specific amount of time or is waiting for a signal from any another thread with timeout.
- Terminated: when a thread either has finished its job, or killed. note that a terminated thread cannot start over again, and it's ready for finalizing.
- Interrupted: this indicates if an interrupt signal has
been sent to the thread or not, note that this is not an actual state, a thread would get interrupted when it's in either running or waiting states
(not in new and terminated states). You cannot get the interrupt state by
the
State
enumeration. - Dead: when thread A is waiting for a signal from thread B, meanwhile thread B is waiting for thread A too, or maybe thread B has sent the signal just before thread A attempts to wait for it (this is
the actual dead lock), here there is nothing left behind to signal the waiting thread.
You need to just program your application in such a way that you ensure there is no dead state. Note that there is no any property or method to find out if a thread is in dead state or not, so if you face with dead lock, this is your bad way of programming. - Thread Priority
MAX_PRIORITY
MIN_PRIORITY
NORM_PRIORITY
(default value)- Daemon mode: this one is used for setting a thread to run as Daemon (background) mode or not. When a thread is in daemon mode, it means it runs until any other user thread (non-daemon) is alive in the application. Whenever there is no user-thread alive, then JVM kills the daemon threads by force (silently). You cannot even get any exception about the exit signal. These kinds of threads are useful when your application needs to have a background-service thread or an event-handler. These threads are usually run in lower priority. Once again, these threads are running within your process, but JVM does not look at them as user threads for checking the life of the process (check the diagram).
Each thread has a unique ID (int value) which is provided by either the runtime or the OS. This is a read-only and unique value.
A name for the thread, it could be the same through many threads. It's useful to categorize threads belonging to a specific module or task.
The current state of the thread. The state of a thread is determined by the State
enumeration, which is one of the following:
Note: in some tutorials, they explain the dead as same as the terminate state, where this is okay, dead state is known as terminated state too, but according to my knowledge dead and terminated are two separated subjects
It indicates the priority of the thread, a higher priority causes more process attention (context switch) to the thread, that could be one of the following:
As the above diagram says, whenever a user thread gets finished, JVM tests if there is any user thread running yet? If there is not, then it kills every running daemon threads silently(by force), so beware of changing(manipulating) something in a daemon thread, if you know it could get killed right now, it's better to signal it before JVM does. We will focus on daemon threads later, just keep reading.
Example
The following example is showing how to set and get thread properties, it's really simple.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) throws InterruptedException {
Runnable r0;//pointers to a thread method
r0=new MyThread();
Thread t0;
t0=new Thread(r0);
System.out.print("T0 thread state before thread start is "+t0.getState()+"\n");
t0.setName("my lucky thread");
t0.setPriority(Thread.MAX_PRIORITY);
t0.start();
Thread.sleep(1000);// wait for 1 sec here
System.out.print("T0 thread state is "+t0.getState()+" right away\n");
//t0.interrupt(); // this method will throw a Interrupt exception at the target thread.
Thread.sleep(5000);
System.out.print("T0 thread state is "+t0.getState()+" right away\n");
}
}
class MyThread implements Runnable{
private String arg;
@Override
public void run() {
Thread t=Thread.currentThread();//returns the running thread, this thread.
System.out.print("HI, my thread name is \""+t.getName()+
"\" and my priority is \""+t.getPriority()+
"\" and my ID is \""+t.getId()+"\"\n");
try{
Thread.sleep(5000);// wait for 5 seconds here
System.out.print("Hallelujah, thread has terminated successfully!\n");
}catch(InterruptedException e){
/*if there is an interrupt signal
* it defines by InterruptedException
* so this catch determine whenever this thread got interrupt ex.
*/
System.out.print("Oops, I've got interrupt message!\n");
}
}
}
Thread's Behaviors
Well, beside properties, a thread has some specific methods too, some of them belong to the thread class, some of them belong to a thread instance, and keywords. Well the basic behaviors (methods) of threads are listed below.
- Start(simultaneously): when the thread need to run simultaneously with dedicated stack, this operation is done by
start()
method. - Sleep: whenever a thread needs to sleep for a particular of time
Thread.sleep(<<time in ms>>)
would help, note that there is no warranty about the exact time. The sleeping process(reminded time) could get skipped if another thread interrupts the sleeping one. - Interrupt: this method is used when another thread needs to interrupt the another one where it is in either wait (and join()), sleep , or even runnable states. For example thread A is waiting for a signal, then thread B interrupt the thread A, here the interrupt message:
- Wakes up the target thread if it's either in wait (wait/join) or sleep state
- Throws the InterruptedException to the target thread, to notify it about the interrupt signal unless the victim is running state.
- Sets the victim interrupted flag to true IF and IF it was in running state when got the interrupt signal.
and the code:
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
package wasys911992.blogger.example.thread;
public class Core {
public static void main(String[] args) {
Runnable r0,r1;
r0=new ThreadA();
Thread threadA,threadB;
threadA=new Thread(r0);
r1=new ThreadB(threadA);//pass the thread A ref to thread B for interruption
threadB=new Thread(r1);
threadA.start();
threadB.start();
}
}
class ThreadA implements Runnable{
@Override
public void run() {
System.out.print("A:I'm doing some operations\n");
//.....some work
try{// try to sleep
System.out.print("A:let's sleep for 10 sec\n");
Thread.sleep(10000); // sleep for 10 sec
}catch(InterruptedException e)//while in sleep mode, interruption would happened
{//handle if interrupted, do alternative tasks
System.out.print("A:Oops, someone sent the interruption siganl and I will finish myself.");
return;//terminate the thread
}
System.out.print("A:I have to be a lucky guy, no any interruption message! thanks \n");
}
}
class ThreadB implements Runnable{
public ThreadB(Thread t){this.threadAref=t;}
Thread threadAref;
@Override
public void run(){
try {
Thread.sleep(5000);//sleeps for 5 sec
threadAref.interrupt();//comment it and see the differences
} catch (InterruptedException e) {
System.out.print("B: I've got an interruption signal, but I will continue my task!\n");
}
System.out.print("B: nothing interesting here!\n");
}
}
As the above figure says, both thread A, and B start their task at a same time, Thread A tries to do something that would take 2 seconds then sleeps for 10 seconds,
meanwhile thread B sleeps for 3 seconds then wakes up and Interrupt the thread A.
Note when a thread is in sleep state, join and wait state:
- Sleep, join or wait operations should surround with try catch block, because of any interruption signal(Exception)
- The interruption is just like a signal, it doesn't force the thread to shutdown
Thread.currentThread()
, it Returns a reference to the currently executing thread object,
but outside the thread you may need to check all the threads or have a references of the thread.Note: this is possible to more than 1 thread is waiting for an object signal. When 3 threads are waiting on an Object, they are standing on notify queue
(not exactly queue, dependence on priority too), it means for very next single notify signal, a thread will be dequeued and signalled.
But the notifyAll()
release all the threads in the queue, we will focus on this section, just keep reading.
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
package wasys911992.blogger.example.thread;
public class Core {
public static void main(String[] args) {
Runnable r0,r1;
r0=new ThreadB();
Thread threadA,threadB;
threadA=new Thread(r0);
r1=new ThreadA(threadA);//pass the thread A ref to thread B for interruption
threadB=new Thread(r1);
threadA.start();
threadB.start();
}
}
class ThreadA implements Runnable{
public ThreadA(Thread t){this.threadBRef=t;}
Thread threadBRef;
@Override
public void run(){
try{
System.out.print("A: Waiting for thread B get finished\n");
threadBRef.join();//wait until threadB is alive
System.out.print("A: thread B has completed almost");
} catch (InterruptedException e) {//like the wait and sleep, join could get the interrupt signal too
System.out.print("A: interrupt signal has received!\n");
}
}
}
class ThreadB implements Runnable{
@Override
public void run() {
try{
Thread.sleep(10);//wait a bit, let the ThreadA goes first (not recommended)
System.out.print("B:doing some work");
for(int i=1;i<10;i++){
System.out.print('.');
Thread.sleep(1500);
}
System.out.print("\n B: Operation completed\n");
Thread.sleep(2500);
}catch(InterruptedException e)
{
System.out.print("B:interrupt signal has received!\n");
}
}
}
I'm really sorry for the following example because this is a little hard for me to find a perfect example for yielding, but when you run the following for several times, you will faced with difference responses(because yield doesn't have a certain behavior), just comment the yield task and see the differences.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static ThreadA threadA;
public static ThreadB threadB;
public static void main(String[] args) throws InterruptedException {
System.setOut(new PrintStream("./out.res"));
Runnable r0=null,r1=null;
Thread a,b;
r0=new ThreadA();
r1=new ThreadB();
threadA=(ThreadA)r0;
threadB=(ThreadB)r1;
a=new Thread(r0);
b=new Thread(r1);
a.start();
b.start();
a.join();
b.join();
System.out.flush();
}
}
class ThreadA implements Runnable{//imagine that two thread A and B cannot sync with other implicitly
public int progress=0,i=0;
@Override
public void run() {
System.out.print("Hello from 1st. thread\r\n");
for(;i<10000;i++){//this is possible this thread perform even 2000+ loop in a switch(turn)
if(Core.threadB.progress + 5 < this.progress && Core.threadB.progress!=100){
System.out.print("A: thread B is out of the date, try to switch [B(thread, loop):"+Core.threadB.progress+" , "+
Core.threadB.i+" A(thread, loop):"+Core.threadA.progress+" , "+Core.threadA.i+"]\r\n");
Thread.yield();//tell host, ignore me now(a bit) and check the others
}
if(i%100==0){System.out.print("Thread A, progress :"+(i/100)+"\r\n");progress++;}
}
}
}
class ThreadB implements Runnable{
public int progress=0,i=0;
@Override
public void run() {
System.out.print("Hello from 2nd. thread\r\n");
for(;i<10000;i++){
if(Core.threadA.progress + 5 < this.progress && Core.threadA.progress!=100){
System.out.print("B: thread A is out of the date, try to switch [B(thread, loop):"+Core.threadB.progress+" , "+
Core.threadB.i+" A(thread, loop):"+Core.threadA.progress+" , "+Core.threadA.i+"]\r\n");
Thread.yield();//tell host, ignore me now(a bit) and check the others
}
if(i%100==0){System.out.print("Thread B, progress :"+(i/100)+"\r\n");progress++;}
}
}
}
The above code is not cool example, but just check the result in the output file and imagine what was going on. Remember that if there are two threads that cannot
sync with each other, using yield()
method may not a good choice. You have to use another pattern and method instead, we will talk about it later.
Other Thread's Behaviors
We have mention about the most used (new-fashion) thread methods and behaviors, but there are still 3 deprecated (old-fashion) methods here, that you need to know the differences with the new ones.
- Suspend and Resume: the old fashion of wait and notify (synchronization), but there is very big difference, first that suspend pauses the thread (as well as wait does) but does not unlock any synchronized(locked) resource, furthermore for resuming the thread, the thread references is required to call the resume method. Where in wait and notify method you just need locked object references.
- Stop: it's looks like interrupt with a big differences, when you stop a thread, it means you are throwing an error(ThreadDeath[not exception] as a signal) at any state to the target thread, like the interrupt you would catch the ThreadDeath error in a catch block and do the alternatives. Notice that interrupting a running thread doesn't throw the interrupted exception to the victim, while stopping a thread throws the thread death to the victim at any state. This would be dangerous because this is possible a thread gets stopped while it locked an resources and was performing an update on it, so here object might get into an in-consistence state.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public final static Object o = new Object();
public final static Object o2 = new Object();
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
Thread y = new Thread(t);
y.start();
Thread.sleep(2200);
y.stop();// throws the ThreadDeath Error to the target thread
synchronized (Core.o2) {
System.out.print("Main thread: Could acquire the Object o2 lock.\n");
}
}
}
class MyThread implements Runnable {
@Override
public void run() {
{
System.out.print("Hi from MyThread!\n");
synchronized (Core.o2) {// lock the o2 object, so the main thread should not access it
while (true) {
try {
synchronized (Core.o) {// lock the o object
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
System.out.print(i + "\n");
}
}
} catch (Exception e) {
System.out.print("I've got an exception, but still holding o2 lock\n");
}
}
}
}
}
}
In above code, Object o2 has locked by an infinitive loop in MyThread
, it means no any thread would access it forever(like the main thread),
but the stop()
method causes throwing a ThreadDeath
Error to the victim, which here it will not catch it, so the victim just got an uncaught exception|error, so it cancels the rest of the work, that means releases all blocked resources like o2, and o1. But if it catches the error, then locked object
won't get released because is still has the control, like the below.
public class Core {
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public final static Object o = new Object();
public final static Object o2 = new Object();
// Source code level: 7
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
Thread y = new Thread(t);
y.start();
Thread.sleep(2200);
y.stop();// throws the ThreadDeath Error to the target thread
synchronized (Core.o2) {
System.out.print("Main thread: Could acquire the Object o2 lock.\n");
}
}
}
class MyThread implements Runnable {
@Override
public void run() {
{
System.out.print("Hi from MyThread!\n");
synchronized (Core.o2) {// lock the o2 object, so the main thread should
// not access it
while (true) {
try {
synchronized (Core.o) {// lock the o object
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
System.out.print(i + "\n");
}
}
} catch (Exception | ThreadDeath e) {// ThreadDeath for handling any stop signal.
System.out.print("I've got an exception or Error, but still holding o2 lock\n");
}
}
}
}
}
}
The differences between this one and the previous is that, the second one also catch the ThreadDeath error too, so the thread still has the control and the o2 Object will be hold in lock state, and next while loop get started.
If you are planning to use them, so just keep your eye on any unexpected error and signal that they would throw.
Synchronizing Threads
Well I would say this is most important section in this tutorial, synchronizing two thread is really important when you are developing a multi-threaded program.
For synchronizing two thread you need a not null shared Object (no primitives).
The lock object usually is actual Object
class, this object(or objects) should be visible(shared) to threads want to sync with each other, so don't forget to pass them to target threads. For instance thread A waits for lock object for a(the) notify signal from thread B that causes thread A exit from wait state and continue its work.
Notes!!!
- More than one thread would wait on an lock object, and one notify call just releases one thread from the waiting queue (dependants on priority, JVM chooses)
- The notifyAll causes whole of the waiting thread get released from the queue
How to Synchronize Two Threads With Each Other?
Okay now, it's kicking time, a simple example would help for start.
Example
Consider a Tick Tock application. First try to analyse the case study by asking some simple questions such as, Where is the start point? does it need threads? how many threads? does it need synchronization? etc...
Well a Tick Tock application starts with saying Tick, then 0.5 sec waiting, next saying Tock, next 0.5 sec waiting and start over again...,
Tick, Tock, Tick, Tock,....., and now lets identify the processes:
- Creating an Object
lock
for synchronization - Creating two thread Tick, and Tock and pass the lock object to them
- Starts the threads parallel
- (in a for loop) Tick says Tick, meanwhile Tock waits for thread Tick for notify signal on lock object
- Tick sleeps for 0.5 seconds, while Tock is still waiting for Tick signal
- Tick sends the notify signal to object lock, and Tock get released from the lock
- Now Tock says Tock, meanwhile Tick waits for thread Tock for notify signal on lock object
- Tock sleeps for 0.5 seconds, while Tick is still waiting for Tock signal
- Tock sends the notify signal to object lock, and Tick get released from the lock
- Back to step 4! until for loops get finished
And the diagram would be like this:
and now before we going for the code, we need to know about locking in java, and it would be easy
synchronized Block
In Java sometimes we need to lock a resource, because we needs to ensure that no any thread won't read or write on that object while it's locked ,so here a locking operation is required by the related thread. It's really easy, it goes like this, with synchronized block.
synchronized(<<lock_Object>>){
//here no any thread won't access (read, write) the lock_Object except the current thread.
}
For waiting and notify on a lock Object, it should locked (synchronized) before either wait, notify, or notifyAll. as below.
//Object will be locked by this thread if it's free to lock, else has to wait until released!
synchronized(lock_Object){
lock_Object.wait();//release the lock, and acquire it again after get notified
}
//lock_Object2.wait();// Error!, should get synchronized like above for either waiting or notifying
Important note: As we said, when a thread locks (synchronized) a resource no any thread would access to that resource.
If a thread invokes wait() method of an object(lock), that object released (release the lock) of the object in order to enable another thread to
acquire the lock and notify the waiting thread. this clause is not necessary for joining, sleeping and yield methods.
If in a synchronized block, thread sleeps for 10 years, it means the synchronized object is locked for 10 years, it means sleeping, joining, and suspending processes don't release any locked resource
okay we have got everything to know to impl our example now.
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static Object lock=new Object();
public static void main(String[] args) throws InterruptedException {
Runnable r0=null,r1=null;
Thread a,b;
r1=new Tock();
b=new Thread(r1);
r0=new Tick(b);
a=new Thread(r0);
a.start();
a.join();
b.join();
System.out.print("Hallelujah, threads finished!");
}
}
class Tick implements Runnable{
private Thread tockThread;
public Tick(Thread t){tockThread=t;}
@Override
public void run() {
tockThread.start();
try{for(int i=0;i<20;i++){
System.out.print("Tick ");
Thread.sleep(500);
synchronized (Core.lock) {
Core.lock.notify();//notify tock, it's his turn [1]
Core.lock.wait();//and wait until tock notify you for next cycle [4]
}
}
}
catch(InterruptedException e){}
}
}
class Tock implements Runnable{
@Override
public void run() {
try{
for(int i=0;i<20;i++){
synchronized (Core.lock) {
Core.lock.wait();//wait for tick completes its turn [2]
}
System.out.print("Tock ("+(i+1)+")\n");
Thread.sleep(500);
synchronized (Core.lock) {
Core.lock.notify();//my turn completed, signal tick for next cycle[3]
}
}
}catch(InterruptedException e){}
}
}
Any question? always beware that wait, notify, and notifyAll need to invoked inside a synchronized block where they locked by the synchronized block.
Notice that if a thread locks object a, then object b, and waits for object b, it means it releases just object b lock, not a.
Synchronized Methods
A method is called synchronized when it locks its hots object (this
).
Please note that while a synchronized method is running on instance a
, no any
threads would invoke the members belonging to it. Also there is no need for synchronized block to lock the host object because the synchronized method does it implicitly
public synchronized void method(Object arg){
//it means this(host) object will be locked by this block (method)
}
public void method(Object arg){
synchronized(this){
//this is same as above
}
}
Let's have a simple example.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static Synch s = new Synch();
public static void main(String[] args) throws InterruptedException {
new Thread(new MyThread()).start();
Thread.sleep(1);// ensure that MyThread go first
new Thread(new MyThread2()).start();
}
}
class MyThread implements Runnable {
@Override
public void run() {
try {
Core.s.intoduceFriends();// calling a synchronized method
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
Core.s.whoAmI();// I should wait for 25 sec
// whole of the Synch object is locked now!
}
}
class Synch {
public synchronized void intoduceFriends() throws InterruptedException {
System.out.print("Fiends are {Danial, Pedram, Armin, Aria, Manochehr, Farzad, Aidin, and you!}\n");
Thread.sleep(25000);
// sleeping 25 sec in a synchronized methood means
// 25 sec of locking the host object (this), no any member will be
// accessible!
}
public synchronized void whoAmI() {// surprise
System.out.print("This example has prepared by https://github.com/911992\n");
}
}
Example
Let's have the above example (tick-tock), but with synchronized methods this time.
package wasys911992.blogger.example.thread;
public class Core {
public static Lock lock=new Lock();
public static void main(String[] args) throws InterruptedException {
Runnable r0=null,r1=null;
Thread a,b;
r1=new Tock();
b=new Thread(r1);
r0=new Tick();
a=new Thread(r0);
a.start();
b.start();
a.join();
b.join();
System.out.print("Hallelujah, threads finished!");
}
}
class Tick implements Runnable{
@Override
public void run() {
try{for(int i=0;i<20;i++){
Core.lock.tickCycle();//notify tock, it's his turn [1]
System.out.print("Tick ");
}
}
catch(InterruptedException e){e.printStackTrace();}
}
}
class Tock implements Runnable{
@Override
public void run() {
try{
for(int i=0;i<20;i++){
Core.lock.tockCycle();//wait for tick completes its turn [2]
System.out.print("Tock ("+(i+1)+")\n");
}
}catch(InterruptedException e){e.printStackTrace();}
}
}
class Lock{
private boolean tickCycle=true;
//synchronized method automatically lock and release this object
public synchronized void tickCycle() throws InterruptedException{
if(!tickCycle){this.wait();}
Thread.sleep(500);
tickCycle=false;
this.notify();
}
public synchronized void tockCycle() throws InterruptedException{
if(tickCycle){this.wait();}
Thread.sleep(500);
tickCycle=true;
this.notify();
}
}
As above example , we have a new member Class name Lock here, that contains two synchronized method, in tickCycle() method, it sleeps for 500 ms, and because it's synchronized, then no any thread would invoke any member of this class, so the tock thread has to wait until tockCycle() member get released (Lock object in fact).
Remember again, sleeping process doesn't release any locked resource.Exercises
And now, it's your turn, try to impl the following case studies, and feel free to contact me for any issue! or even evaluate your impl.
- Just try to extend the above example with Tick Tock Tack!
- A program starts to write 10 large file down in the hard disk with a heavy process of data(as you wish, could be combination of shifting, square, sqrt, etc...), meanwhile a thread shows the overall process(%).
- A graphical shooting game, user has got 2 minutes to shoot random-placed circles in game screen.
volatile
Keyword
Hint
We have two kinds of updating a variable in programming, direct-modify, and read-modify. The only difference is just in read-modify mode, data is read, then it is updated (likei=i+10;a++;a+-1990;
), but in direct-modify mode data is updated directly without depending to the exist value(like i=1990;a="FOLKS!"
).Case Study
In a parallel program, this is possible that two threads want to access(either set or get) a variable concurrently, for example
two threads, one of them is updating value i
, meanwhile another one wants to read it, so here inconsistency would appear because when the variable is being updated, another thread just attempts to read it, therefore it's possible old value is read.
So (by default) there is no warranty force the second thread to wait updating thread finishes updating, then read(wait for) the new value.
Solution
For solving the issue, we must lock the variable for each update, but there is another(easier) solution for direct-modify updates to lock the variable during the update by setting the variable volatile.Remember volatile does not lock the object. It's used when there is a thread(s) updating(direct-modify) a variable, simultaneously a thread(s) needs to read it(like an auction system). Here volatile ensures that the reading thread will get the very last update, then the thread(s) will be waited until all the updating threads finish(if any).
And now when should we use volatile? and when must use synchronized block instead?
- If a variable is updated directly(like i=1.59F, i='A', i=0Xa19caa90e4d), use volatile.
- If a variable is updated based on current value (like i=i+1, i%=7, i=1.9944D-i*2.1), use synchronized thread/block.
This is possible to replace all of the volatile way to synchronized way. A volatile variable would be either primitive or objective also could be null too, while we just can lock not-null objects by synchronized blocks.
How to Set a Variable Volatile?
Simple, use volatile keyword with variable declaration.
public class Invoker{
public volatile Object obj;//it could be null
private volatile int id;//it could be primitive too
public int getId(){
return this.id;//because id is volatile, so if there is an update in progress,
// it(current thread) waits for the last update, then return the updated value.
}
}
Example
Now lets have some example, make a decision to use either volatile or synchronized approach.
Last User logged on
Consider an application tracks(set and get) the last user id has logged into the system. First we have to analysis it, does it accept asynchronous requests? yes of course, because data would be updated or read concurrently. Okay, next we need to figure out how does user id get updated? The variable is updated as direct-modify mode, in other word it doesn't dependent to the current value, then here the volatile approach would help within setting and getting the value.
public class SysMgr{
private volatile long lastUserId=-1L;
public void set(long lui){ this.lastUserId=lui; }
public long get(){ return this.lastUserId;}
}
If a thread(A) wants to get the lastUserId value, and simultaneously another thread(B) is updating it, then the thread A will be waited(blocked) till thread B completes the update, then return the new value to thread A, and all of these are because of volatile keyword.
Total Login Count
An application that would count, how many times does system have login.
This example is a bit like the previous one, except one thing. For counting you have to update an current value. In other word update process is read-modify one. Then for this case volatile would not help, because volatile does not lock the variable while it's updating in processor level(register/cache). But it could be handy if there is a count reset function needed. The code would be like this, variable definition will be volatile for readers and direct-set value, and a synchronized method to ensure there is only one thread is updating value.
public class Statistic{
private volatile long logins=0L;
public synchronized void newLogin(){logins++;}//jus one thread is allowed to access this method
public long getValue(){return this.logins;}//the variable logins is volatile, so it returns the very last update value
public void reset(){this.logins=0;}//it could be without locking, because the update is direct-modify
/*
* some members
*/
}
The getValue()
is not synchronized, and this is not required, because for any reading, this ensures you committed(new) value will be returned.
Note that getValue()
method must be synchronized if logins variable was not volatile.
Relative and Absolute Update
Yet another example
public class Mgr{
private volatile long l=0L;
public synchronized void increment(){l++;}//this is read-modify update, so needs the lock
public void set(long l){this.l=l;}//this is just modify update, so could be done with volatile
}
Notes
Okay Okay Okay, I would say now you would write any multi-thread application by your hands, but still there are some important things left behind you need to know about them. Like patterns, issues, managements and...
Main Thread
If an application has got a main method, then JVM creates a thread named main thread, and invokes the main method with this thread.
Creating Thread
In Java there are two ways for creating (declaring) a thread, Implementing Runnable
interface or extending by Thread
class, which the first way is more common. like the below:
class MyThread implements Runnable{//recommended
//@Override
public void run() {/*Your business goes here*/}
}
And the second approach.
class MyThread2 extends Thread{ //@Override public void run() {/*Your business goes here*/} }
Daemon Threads
As we mentioned, there are two kinds(by the running method) of threads in Java, user-threads, and daemon-threads. JVM kills and purges the memory
of your application when there is no any user-thread running, also kills daemon-threads(if any) silently. So beware about the daemon-threads.
Try not change something if you know application could be finished right now, because daemon threads would not receive any interrupted or thread death signal. but if you do signal them implicitly before all your user threads get terminated.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
Thread y = new Thread(t);
y.setDaemon(true);
// you have to set it before you start it!
// set it as false and run the code again, see the differences
y.start();
Thread.sleep(5200);
System.out.print("The very last result from our daemon-thread: "+t.res+"\n");
System.out.print("Main thread has terminated, no any user thread available no more!\n");
}
}
class MyThread implements Runnable {
long res = 0X0L;
@Override
public void run() {
{
System.out.print("Hello, I am a daemon thread, wohaha!\n");
while (true) {
try {
for (int i = 0; i < 10; i++) {// if I be a lucky thread, I will reach the 10
Thread.sleep(1000);
res += i;//it's unsafe, but we don't care, not important.
System.out.print("Res variable value now -->" + res + "\n");
}
} catch (Exception | ThreadDeath e) {// catch for any stop() or interrupt() signal
System.out.print("I will never get any signal by JVM, for-ever daemon >:D \n");
}
}
}
}
}
You must set a thread as daemon before start it, MyThread has a for loop that takes 10 sec to finish, but because it is a daemon, it will killed by JVM when the main thread gets terminated.
Shutting Down a Thread
Well as we mentioned, there is no any certain method for shutting down a thread, so you really cannot force a thread to shutdown. Then you need to design a way to signal a thread to stop working. One way is using interrupt()
method and interrupted
flag state of the thread, this is not recommended, because interrupt has designed for waking up a thread when it's in either one of sleep, join, or wait state.
Note when we invoke interrupt method, it could have different behaviors.
- If a thread is in either wait, join or sleep state, then the rest of the sleep/wait state will be omitted and an InterruptedException will be sent to the victim thread.
- If a thread is blocked by some IO operation ,then the interrupt signal will be queued once the thread blocked down, then the signal will be affected.
- If a thread is blocked by some NIO operation ,then the rest of the sleep/wait state omitted, the IO channel get closed and a ClosedByInterruptException sent to the thread by JVM.
- If a thread is in runnable state, then just the interrupted flag will be set to true.
- If a thread is in new state(hasn't started yet), then nothing will be happened!.
So here we could use the interrupted flag as shutdown flag to signal the victim thread to stop working.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {//Just run it for several times, you will faced with different results
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
Thread y = new Thread(t);
y.start();
Thread.sleep(2);// wait 2 ms, see how much your system strong is in 2 ms?
y.interrupt();//set the interrupted flag to true
System.out.print("Main thread: I've send the interrupt(shutdown) signal\n");
}
}
class MyThread implements Runnable {
int i=1;
@Override
public void run() {
while(Thread.currentThread().isInterrupted()==false){//until this thread hasn't got any interrupt signal
double a=0.0D;
for(int k=100;k>i;k--){
a=k*k*2/5*Math.pow(2, k);//some operations.....
a=Math.sqrt(a);
}
System.out.print("Res("+i+"): "+a+"\n");
i=i+1;
}
System.out.print("I've got an interrupt signal :(\n");
}
}
As you see MyThread continues its work until another thread set its interrupted flag to true. Note that in MyThread, there is no any try catch, because as we mentioned, if thread is in running state the interrupt()
method just sets the interrupted flag to true.
As the above code works without any problem, but this is recommended use an implicit way to signalling a thread for stopping working.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
Thread y = new Thread(t);
y.start();
Thread.sleep(2);// wait 2 ms, see how much your system is strong in 10 ms?
t.shutdown();
System.out.print("Main thread: I've send the interrupt(shutdown) signal\n");
}
}
class MyThread implements Runnable {
private volatile boolean shutdown=false;//use a user shutdown flag
public void shutdown(){this.shutdown=true;}//a method instead of interrupt method for sending the shutdown signal.
int i=1;
@Override
public void run() {
while(this.shutdown==false){//until shutdown signal hasn't sent
double a=0.0D;
//some big load!
for(int k=100;k>i;k--){
a=k*k*2/5*Math.pow(2, k);
a=Math.sqrt(a);
}
System.out.print("Res("+i+"): "+a+"\n");
i=i+1;
}
System.out.print("I've got an interrupt signal :(\n");
}
}
The differences is just about the shutdown flag, one of them via interrupted flag, and another one with customized user flag, which I recommend the second one.
wait(1000) VS. sleep(1000)
We have mentioned about the wait()
and sleep()
methods, let's review the behaviors of two these guys.
wait()
It releases the synchronized(locked) object, and waits until another thread notifies(either notify, stop or interrupt) it, then after it gets notified(if by notify) it tries to acquire the lock again and continues its work. Note that a waiting thread has to acquire its lock again on the related object after it gets notified.
sleep()
It doesn't release any locked object, and sleeps for a specified amount of time, but this time could get skipped(wake up) by either stop or interrupt signals.
But here we could wait (wait(max_of_wait_time)) for a notify signal with timeout. It means thread releases the locked object and waits for notify signal,but it will notify itself if no any thread notifies it by the timeout.
synchronized(lockObj){
lockObj.wait();//releases the lockObj(just lockObj) and waits for notify signal, even if it could be 2 years
}
synchronized(lockObj){
lockObj.wait(20000);//releases the lockObj and waits for notify signal,
// but it will notify (and acquires lock again) itself after 20 sec
}
synchronized(lockObj){
Thread.sleep(20000);//just sleep for 20 sec
}
So the only differences between wait(1000) and sleep(1000) is, wait(1000) sleeps for 1 sec and releases the locked object too, while sleep() doesn't release the lock.
Switching Between Threads (mistrustful yield()
)
What does switching mean exactly? so it's a really easy peasy subject, a single thread/single core CPU would run only one job at a time. So for running a parallel application or some process, it has to switch to another thread/process and does some task of another threads too. Then so how do we see everything smooth? because a CPU is really powerful(cheers), switching between threads would be even less than 10 nano seconds!
When you want to switch between your threads, you would do it implicitly(direct) by wait and notify, or explicitly(in-direct).
We use notify/wait approach when the order of running threads are important for us, for example must run step B after step C. The following diagram is showing possible thread switching between two un-synchronized threads, but note that it's even possible CPU completes whole of the thread one then switches to thread two, or does 1% of thread 1, switches to thread 2 and does it 100%, then switches back to thread 1 and completes the thread 1, too much possibilities.
As you see, there is no warranty that ensures you two (same time start) concurrent thread get finished at a time too, unless you synchronize them with each other.
But when there is no(no need to) any wait and notify method, how to switch(try switch) to another thread? we have mentioned about yield()
method that could be handy, but this guys is kinda untrustworthy, the yield calls an underlying OS function for switching between threads, it says system would skip the current(this) thread and switch to another one. but sometimes you see no any differences, and OS simply ignores the call.
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) throws InterruptedException {
new Thread(new MyThread()).start();
new Thread(new MyThread2()).start();
//no one knows when this print will get invoked! after thread 1? or even 2? or even after them?
System.out.print("Main Thread: I started the threads :)\n");//main thread sentence [S]
}
}
class MyThread implements Runnable {
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.print("Thread 1: "+i+"\n");
}
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
for(int i=0;i<20;i++){
System.out.print("Thread 2: "+i+"\n");
}
}
}
Just run the above code many times and you will see many results, even I got this result (whole thread 1, whole thread 2, and then main thread).
Okay now let's have a use case, we want trying to wait thread 1 and thread 2 for a bit, and let the main thread says its sentence ([S] section) first, then switch back to them, first let's have it with yield method, in the thread 1, and thread 2 we call yield method, it means skip this (thread 1 and thread 2), and switch to another thread. check the new threads methods.
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
class MyThread implements Runnable {
@Override
public void run() {
Thread.yield();//tells host you would skip me, switch to others.
for(int i=0;i<20;i++){
System.out.print("Thread 1: "+i+"\n");
}
}
}
if you ask me, I would say there is no any differences! and this is because many geeks try not to use it, but here what should we do?
One solution is sleeps implicitly for a small amount of time, but remember when you sleep for 1 ms, it doesn't mean the system will comeback exactly after 1 ms.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) throws InterruptedException {
new Thread(new MyThread()).start();
new Thread(new MyThread2()).start();
//no one knows when this print will get invoked! after thread 1? or even 2? or even before them?
System.out.print("Main Thread: I started the threads :)\n");// main thread sentence [S]
}
}
class MyThread implements Runnable {
@Override
public void run() {
try {
Thread.sleep(0, 50);//if system doesn't sleep me, I sleep myself for 50 nano seconds! , wohaha
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<20;i++){
System.out.print("Thread 1: "+i+"\n");
}
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
try {
Thread.sleep(0, 50);//but still there is no warranty!
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<20;i++){
System.out.print("Thread 2: "+i+"\n");
}
}
}
In the above code, we just replaced the yield method with sleeping for 50 nano seconds! but still I'm not sure that main thread sentence [S] goes first, there is more chance that main thread goes first here, but I say again, there is still no any warranty that force thread1 and thread 2 go after thread main even if you sleep for 2 seconds instead of 50 nano seconds, unless you synchronize them.
Notice that it dependants on your CPU too, if your CPU(FSB-RAM) is strong enough then 50 nano seconds is good enough to switch to another, but another CPU may needs more!, the busy level of the system would effect too.
Advanced Topics
There is no room for low-performance apps, so let's talk professionally, here we want to talk about advanced topics, but remember this article for beginners.
Manage Your Memory
Each thread has a private memory which is accessible to itself(methods, classes, etc...), and a shared memory which is belong to every threads, note that these resources (memory) are separated into two types, some of them are generated and managed by you (developer), and some of them (like thread id, stacks, properties, etc...) are belong
to host (either JVM or OS).
Then beware of creating to much threads, it would eat whole of your memory/resource very easy. Executing a sequential(serial, single-thread) application is more more more easier than a multi-thread application for the CPU, but we should not worry about the CPU easy work, we need our process ASAP with minimum process would take. Now just run the following code to see yourself how many threads would disturb your system, and watch your system memory and performance.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public final static Object o=new Object();
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<5000;i++){//what if running 5000 threads, watch your system!
new Thread(new MyThread()).start();
}
}
}
class MyThread implements Runnable{
//there are no any user variable
@Override
public void run() {
//some work
try{
synchronized (Core.o) {
Core.o.wait();
}
}catch(Exception e){
}
}
}
What if there are 5000 of threads in memory!?, some are waiting for garbage collector, some are waiting, some are sleeping, and some are idle, it's just a disaster, but it is would get solved with patterns, just keep reading.
Note that 5000 thread in an application is not a disaster, because you would run over 100000 threads on a GPU, 5000 thread is a little hard to manage for the CPU(also manage the memory), so later you ought to separate your application into concurrent and serial modules (execution flow), and separate the code between GPU and CPU.
Semaphore, Limiting Maximum of Running Threads(a Resource)
The semaphore is a pattern that would be used for limiting the maximum of running thread, this is very useful to prevent your application from running too much threads that may causes memory and process(execution-time) issues.
This is useful when your application is small (not recommended for big applications). There is a good implemented semaphore class available by Java SE API, but I suggest you do it yourself at least for one time to figure out what a semaphore really does!?
For having a semaphore, you have to know what does it do exactly. Semaphore looks like a permitting system, at time t0 you want to run a thread, so first you have to get the permission of semaphore. Semaphore tracks(counts) every running threads and decides to either approves, blocks or rejects you.
The above semaphore tracks the all running threads (in-direct) by counting them. Note that thread must inform the semaphore when it finishes. This kind of semaphore is known as counting semaphore, and now let's have a simple impl.
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
public class Core {
public static void main(String[] args) throws InterruptedException {
System.out.print("trying to run 300 threads, but max 16 thread at a time\n");
MySemaphore sem=new MySemaphore(16);//it could be 8, 32, or even 32, dependent to your application business
for(int i=0;i<300;i++){
sem.acquire();//get a permission to run a thread [1]
new Thread(new MyThread(sem,i)).start(); //run a thread [3]
}
Thread.sleep(100);
System.out.print("Completed :v\n");
}
}
class MyThread implements Runnable {
MySemaphore sem;int val;
public MyThread(MySemaphore sem,int val){
this.sem=sem;//pass the semaphore to client run, to release itself after it gets terminated
this.val=val;
}
@Override
public void run() {
try{
System.out.print("Hello from client run\n client No: "+this.val+"\n");
Thread.sleep(1000);
}catch(Exception e){e.printStackTrace();}
finally{
sem.release(); //tells the semaphore this thread has finished [4]
}
}
}
class MySemaphore{
int maxThreadSize;
int runningThreadSize=0;
Object lock=new Object(),elock=new Object();
public MySemaphore(int maxThreadSize){
this.maxThreadSize=maxThreadSize;
}
public synchronized void acquire() throws InterruptedException{
if(runningThreadSize==maxThreadSize){//checks is it possible to run a thread at this time?
this.wait();//or should wait until another thread get finished [2]
}
runningThreadSize++;
}
public synchronized void release(){
runningThreadSize--;//decrease one thread from runningThreadSize
this.notify();//notify any waiting thread (if any) [5]
}
}
The above example is about running 300 thread which this is not a good idea to run every 300 threads at a time, we want to limit it(at a time) with semaphore.
The main thread gets a permission for each 300 thread to run, and semaphore has to decide to either wait or approve the request, if maximum of threads are running, then semaphore blocks the thread until one of the threads(running threads) gets terminated and signals the semaphore, so semaphore ensures that one thread got finished, and it's possible to run a new one. Simply, you would reject (throw an exception, error, false,...) the requesting thread instead of block it.
Recyclable Threads (Thread Pool)
As mentioned, a thread has got some properties(takes some memory), but there is one important thing belongs them, either OS or JVM don't care about what's going on (execution flow)
within a thread. All the thing they know is that running a thread.
This is like a postman, it brings an envelop to a destination and doesn't care what is inside, next the envelop packet get destroyed, and a new packet is used for the new one. So it's time-consuming about destroying and creating a new packet. So the question is, why don't we use the old packet for the next envelop too? or why don't use the existing thread for running the next business too?
But when we implement a thread (runnable) that copies two files in a flash disk, then this thread just copies two files in a flash disk forever, here we have to impl our thread in such a way that be independent to any business, a thread should be a thread, not a business!
This could be done very easy by thread pools.
As the above figure shows, a thread is got from the thread pool, it does something and has to back to the pool for the next possible request. Result the thread should be independent of any businesses.
public interface ThreadFace{
public void run();//it could return something too, dependants on your design
}
///////////////////////////////////////////
//file Runner.java
public final class Runner implements Runnable{//NOTE: incomplete code!
private ThreadFace tf;//contains the target business, that should get run (is provided by client)
@Override
public void run(){
tf.run();//runs the client business code
}
}
Yet more detailed snippet.
//file ThreadFace.java
public interface ThreadFace{
public void run();//it could return something too, dependent on your design
}
///////////////////////////////////////////
//file Runner.java
public final class Runner implements Runnable{//NOTE: incomplete code!
private Thread thisThread;
private Object wait=new Object();
private boolean shutdown=false;
private ThreadFace tf;//contains the target business need to be run (is provided by client)
void runIt(ThreadFace tf){this.tf=tf;
synchronized(wait){wait.notify();}//signal the run(actual thread) that a new job has arrived, run it
}
@Override
public void run(){
this.thisThread=Thread.currentThread();
while(!shutdown){
synchronized (wait){ wait.wait();/*wait for some job*/}
tf.run();//runs the clients business
this.sendFinSignal();
}
}
private void sendFinSignal(){
//tells thread pool that this job has been finished, take me back to the pool
}
void shutdown(){
this.shutdown=true;
this.thisThread.interrupt();//interrupt the current thread, or stop it if it's necessary
}
}
//
The above code is just part of a simple thread pool, we haven't designed thread pool yet, the following class diagram is for guys who understand UML, contains the members we need for our thread pool.
Let me start with interfaces, as you see there are three(3) interfaces is used in our design.
ThreadFace
This interface is used as a bridge between actual thread and the business that contains a void method which does not accept any argument(as same as actual Runnable interface).
interface ThreadFace{
public void run();//looks like the Runnable, but could be in another face too
}
ThreadPool
This interface is used for communication between clients and thread pool. Client needs to pass ThreadFace's (implementation) instance to the ThreadPool, then actual ThreadPool (ThreadPoolImpl) makes a decision to either runs it immediately(if it's possible) or waits/blocks the client until a new ready thread appeared.
As the previous diagram shows, client sends its request (by ThreadFace) to the ThreadPool (ThreadPoolImpl), and if there is an idle thread available, then thread will run immediately, else client has to wait (blocked by pool) until a thread finishes its job and returns to the pool. Also note because actual threads (Runner) are immortal(in a true while loop) so this interface has got another method for shutting down them.
interface ThreadPool{
public void run(ThreadFace tf)throws InterruptedException;//for running something
public void finilizePool();//for shutting down the pool
}
ThreadPoolComm
This interface is used for communicating between actual threads (Runner) and the thread pool (ThreadPoolImpl), whenever a thread finishes its job, it inducts the thread pool with this interface.
interface ThreadPoolComm{
public void backToPool(Runner r);//for signal and heading back to the pool
}
Okay, and now time for classes.
Runner
I would call it actual thread, this class implements the Runnable interface, and it means it could be a thread, this class just communicates
with ThreadPoolComm and ThreadFace interfaces, inside the run method it runs the ThreadFace interface passed by ThreadPoolImpl class.
This class is run by the ThreadPool, and waits for a signal for a request, after it notified by pool, it runs the ThreadFace's run method then finally signals the pool to head back to the thread pool again for the next request.
final class Runner implements Runnable{
private Thread thisThread;//for keeping the current(this) thread instance
public Runner(ThreadPoolComm tpc){this.tpc=tpc;}//get the pool communicator interface by constructor
private ThreadPoolComm tpc;
private Object wait=new Object();
private volatile boolean shutdown=false;
private ThreadFace tf;//contains the target business, that should get run (is provided by client)
public void runIt(ThreadFace tf){this.tf=tf;//for any request, thread pool calls this method
synchronized(this.wait){this.wait.notify();}
//signal the run(actual thread) that a new job has arrived, run it! [2]
}
@Override
public void run(){
this.thisThread=Thread.currentThread();//getting current(this) thread
while(shutdown==false){//while it has to roll!
try{
synchronized (this.wait){
this.wait.wait();//wait until this thread gets a job [1]
tf.run();//runs the client business code [3]
}
}catch(Throwable e){
//logging, any alternative operation, etc... [b]
}
this.sendFinSignal();//heading back to the pool [4]
}
System.out.print("A Runner thread wrapper has stopped\n");// [c]
}
private void sendFinSignal(){
tpc.backToPool(this);
//tells thread pool that this job has been finished, take me back to pool
}
void shutdown(){
this.shutdown=true;//set the shutdown flag to true
this.thisThread.interrupt();//interrupt the thread [a]
}
}
ThreadPoolImpl
This class manages everything, it gets the ThreadFace object by the client and passes it to Runner to run it. It also generates and manages the Runner instances.
Whenever a client needs to run its ThreadFace, this class checks about ready(idle) threads? if there is one, then passes the ThreadFace object to the Runner object and job will be got started. If no, blocks the client for a thread.
This class contains two list of Runner class, readyPool and runningPool. First one contains idle(ready) threads are ready for action, and second one contains threads are in action(busy).
Note when we use a thread pool, we want to limit the maximum running thread at a time, and recycle the threads too. So most of the time there is only one instance of this class is enough, so we would turn this guy on as singleton.
public class ThreadPoolImpl implements ThreadPool, ThreadPoolComm{
public static void main(String[] args) throws InterruptedException{
ThreadPool pool=ThreadPoolImpl.getInstance();
for(int i=0;i<1024;i++){
pool.run(new Client(i));
Thread.sleep(10);
}
Thread.sleep(2000);
pool.finilizePool();
}
private int poolSize=32;//the size of the pool (threads), it could be anything
private static ThreadPoolImpl instance=new ThreadPoolImpl();// let's have a instance inside, just one!
private List<Runner> readyPool,runningPool;//two list of Runners(threads), ready ones, and busy ones
public static ThreadPool getInstance(){//get the instance with this guy
return ThreadPoolImpl.instance;
}
private ThreadPoolImpl(){//hide the constructor, so no one will be able to create one
System.out.print("Thread Pool Initializing....\n");
readyPool=new ArrayList<>(poolSize);
runningPool=new ArrayList<>(poolSize);
for(int i=0;i<poolSize;i++){//filling the pool
Runner r=new Runner(this);//pass the ThreadPoolComm to the thread(this)
new Thread(r).start();// starts each thread by their creation or we could do it later by their first request
readyPool.add(r);//add the ready thread to ready pool
}
System.out.print("Thread Pool initialized with "+poolSize+" threads\n");
}
@Override
public synchronized void run(ThreadFace tf) throws InterruptedException {
if(readyPool.size()==0){//checks, is there any available thread? [1]
// System.out.print("no any Threads available, wait!\n");
this.wait();//if no, so wait until one heads back
}Runner r=readyPool.get(0);//get the first thread object from the list [2]
readyPool.remove(0);//remove the thread from the ready pool [3]
runningPool.add(r);//add it to busy pool [4]
r.runIt(tf);//signal it, to run the clients code [5]
//System.out.print("Thread run\n");
}
@Override
public synchronized void backToPool(Runner r) {//called when a thread finishes its job
readyPool.add(r);//add the thread to ready pool [6]
runningPool.remove(r); //remove the thread from the busy thread [7]
this.notify();//notify waiting thread(if any) that a ready thread is available [0=8]
}
@Override
public synchronized void finilizePool() {
for(Runner r : readyPool){
r.shutdown();//send shutdown to every ready threads
}
for(Runner r : runningPool){
r.shutdown();//send shutdown to every running threads
}
}
}
Client
It could be anything, it dependents on the business, but here we have a very very simple one.
class Client implements ThreadFace {
public Client(int i) {
this.i = i;
}
int i;
@Override
public void run() {
System.out.print("Hello! thread no:" + i + " \n");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And now the whole code
package wasys911992.blogger.example.thread;
/**
* by https://github.com/911992
* arashmd.blogspot.com
*/
import java.util.ArrayList;
import java.util.List;
public class ThreadPoolImpl implements ThreadPool, ThreadPoolComm {
public static void main(String[] args) throws InterruptedException {
ThreadPool pool = ThreadPoolImpl.getInstance();
for (int i = 0; i < 1024; i++) {
pool.run(new Client(i));
Thread.sleep(10);
}
Thread.sleep(2000);
pool.finilizePool();
}
private int poolSize = 32;// the size of the pool (threads), it could be
// anything
private static ThreadPoolImpl instance = new ThreadPoolImpl();// let's have a
// instance
// inside, just
// one!
private List<Runner> readyPool, runningPool;// two list of Runners(threads),
// ready ones, and busy ones
public static ThreadPool getInstance() {// get the instance with this guy
return ThreadPoolImpl.instance;
}
private ThreadPoolImpl() {// hide the constructor, so no one will be able to
// create one
System.out.print("Thread Pool Initializing....\n");
readyPool = new ArrayList<Runner>(poolSize);
runningPool = new ArrayList<Runner>(poolSize);
for (int i = 0; i < poolSize; i++) {// filling the pool
Runner r = new Runner(this);// pass the ThreadPoolComm to the thread(this)
new Thread(r).start();// starts each thread by their creation
readyPool.add(r);// add the ready thread to ready pool
}
System.out.print("Thread Pool initialized with " + poolSize + " threads\n");
}
@Override
public synchronized void run(ThreadFace tf) throws InterruptedException {
if (readyPool.size() == 0) {// checks, is there any available thread? [1]
// System.out.print("no any Threads available, wait!\n");
this.wait();// if no, so wait until one heads back
}
Runner r = readyPool.get(0);// get the first thread object from the list [2]
readyPool.remove(0);// remove the thread from the ready pool [3]
runningPool.add(r);// add it to busy pool [4]
r.runIt(tf);// signal it, to run the clients code [5]
// System.out.print("Thread run\n");
}
@Override
public synchronized void backToPool(Runner r) {// called when a thread
// finishes its job
readyPool.add(r);// add the thread to ready pool [6]
runningPool.remove(r); // remove the thread from the busy thread [7]
this.notify();// notify waiting thread(if any) that a ready thread is
// available [0=8]
}
@Override
public synchronized void finilizePool() {
for (Runner r : readyPool) {
r.shutdown();// send shutdown to every ready threads
}
for (Runner r : runningPool) {
r.shutdown();// send shutdown to every running threads
}
}
}
interface ThreadPool {
public void run(ThreadFace tf) throws InterruptedException;
public void finilizePool();
}
interface ThreadFace {
public void run();
}
interface ThreadPoolComm {
public void backToPool(Runner r);
}
final class Runner implements Runnable {
private Thread thisThread;// for storing the current(this) thread
public Runner(ThreadPoolComm tpc) {
this.tpc = tpc;
}// get the pool communicator interface by constructor
private ThreadPoolComm tpc;
private Object wait = new Object();
private volatile boolean shutdown = false;// there is no any read and update at same
// time situation, so it's could be not
// volatile
private ThreadFace tf;// contains the target business, that should get run (is
// provided by client)
public void runIt(ThreadFace tf) {
this.tf = tf;// for any request, thread pool calls this method
synchronized (this.wait) {
this.wait.notify();
}// signal the run(actual thread) that a new job has arrived, run it! [2]
}
@Override
public void run() {
this.thisThread = Thread.currentThread();// getting current(this) thread
synchronized (this.wait) {
while (shutdown == false) {// while it has to roll!
try {
this.wait.wait();// wait until this thread gets a job [1]
tf.run();// runs the client business code [3]
} catch (Throwable e) {
// logging, any alternative operation, etc... [b]
}
this.sendFinSignal();// heading back to the pool [4]
}
}
System.out.print("A Runner thread wrapper has stopped\n");// [c]
}
private void sendFinSignal() {
tpc.backToPool(this);
// tells thread pool that this job has been finished, take me back to pool
}
void shutdown() {// thread pool signal this thread for shutting down itself
// completely (application should get shutdown)
this.shutdown = true;// set the shutdown flag to true
this.thisThread.interrupt();// interrupt the thread [a]
}
}
class Client implements ThreadFace {
public Client(int i) {
this.i = i;
}
int i;
@Override
public void run() {
System.out.print("Hello! thread no:" + i + " \n");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Just run the above code, meanwhile monitor your system. This runs smooth, because 32 threads for CPU are not to much hard to execute (at least better than 5000 at the same time), also the most important thing is that a thread is used many times. There is no time needed to destroying and creating threads for every thread and this is the main advantage over semaphore.
Alright, I have described enough, you would find some example here. And once again, for any issues, questions, problems, just feel free to contact me, have a good concurrent program.
Read it offline(pdf).