Java Thread Tutorial
In programming, sometimes you need to do something together (simultaneously),
for example copying a file and showing the copying progress by a
progress bar, or playing a music while showing pictures in slide mode,
or ready for cancel command while copying a file, if a program needs to
do more than one task (thread) at a time, this kind of program is called concurrent (multi-thread) program
Well the main problem with multi-threaded programs is the synchronization between running threads, because each thread wants to finish its process ASAP, for example, a program with two three thread which each thread has a for while inside it, and each iteration prints A, B, C. by default, there is not any warranty that because they start at a same time, they get finished at a same time too, maybe 3rd. thread finishes its work before 1st. and 2nd. threads
Synchronizing threads is not a wonderful or hard work, it could be done very easily, but would complex your application too, but not very hard as killing a dragon in a forgotten castle.
Table of Contents
but sometimes you cannot go through multi-thread application, and this situation is identified very easy, whenever the B task is completely dependent on task A, here these two task cannot run concurrently. as I said, completely, even if 90% is dependent, it could be concurrent.
please note that in concurrent applications, we want to get the maximum of the power of the processor, either GPU or CPU, if a file conversion utilizes 10% of CPU, why don't we run 10 concurrent thread to utilize 100% of CPU and reduce the execution time 10 times?!
the Runnable interface just have a void method called run which does not accept any argument, so for any input you would pass it via the class has just implemented it, just check out the examples.
Well the main problem with multi-threaded programs is the synchronization between running threads, because each thread wants to finish its process ASAP, for example, a program with two three thread which each thread has a for while inside it, and each iteration prints A, B, C. by default, there is not any warranty that because they start at a same time, they get finished at a same time too, maybe 3rd. thread finishes its work before 1st. and 2nd. threads
Synchronizing threads is not a wonderful or hard work, it could be done very easily, but would complex your application too, but not very hard as killing a dragon in a forgotten castle.
Table of Contents
Why Concurrent Programs?
I answer this question with another question, why single-thread programs? in an application sometimes some tasks need to run together, specially in graphical user interface, for example a simple game, you have to track time, manage the objects, play the sounds at a time, this is have to be in a multi-thread manner, or even a simple program that calling a uri, user wants to cancel the operation and it should be in two separated threads, in fact we have to separate a program into small units that would work concurrently. for example if you want to convert 10 files to a particular format, because there is no any dependency between files, this application would do 10 files conversion at a time.but sometimes you cannot go through multi-thread application, and this situation is identified very easy, whenever the B task is completely dependent on task A, here these two task cannot run concurrently. as I said, completely, even if 90% is dependent, it could be concurrent.
please note that in concurrent applications, we want to get the maximum of the power of the processor, either GPU or CPU, if a file conversion utilizes 10% of CPU, why don't we run 10 concurrent thread to utilize 100% of CPU and reduce the execution time 10 times?!
Creating Thread
so first of all, we need to know how to create a thread in our application, in Java language a thread is specified with Runnable interface, in the C/C++ there is not a certain impl of thread, some libs available, but if you ask me, I suggest the pthread, but here we just focus on Java and believe me if you found what are belong to a multi-thread application, you would do it with any language, any libraryJava
in java language as mentioned the Runnable interface is used for specifying a thread, but Thread class starts the thread, it gets an implementation of Runnable and starts the thread either in a separated thread or current thread.the Runnable interface just have a void method called run which does not accept any argument, so for any input you would pass it via the class has just implemented it, just check out the examples.
Example
the following example is just about a two thread that get started from the main thread (first thread)package arash.blogger.example.thread; public class Core { public static void main(String[] args) { Runnable r0,r1;//pointers to a thread method 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 faced with different response, this is because threads have Race condition, it means each thread wants to finish its job ASAP(it's not belong to JVM or OS, belongs to CPU) ,and here the above example is just talked about two thread without any synchronization. the following diagram is showing how does the above code goes.
Exercises
and now, this is your turn, just stop using ctrl+c and ctrl+v, and try to do following practices (you would send it to me if I could help you out with the issues and logical problems)- Develop a program like above example starts with 2 thread, then 2nd and 1sT thread will create two another thread by their thread.
- A program that creates 100 randomized name folder concurrently
Passing argument(s) to threads
it's really easy to pass a value to a thread, but it impossible with the Runnable implicitly. it's easy as ABC to pass argument(s) by the implemented class, constructor, setters, etc...Example
check out the following example for better understandingpackage arash.blogger.example.thread; 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 SecondIteration si=new SecondIteration(); si.setArg("Pedram");// pass arg to thread 2 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"); } } }The above example we have passed a String as value, but you may would pass another type of Object, but remember that it should get passed by the hosted class (impl class)
Exercises
and now, here is your turn, try to do following, and just fell free to contact me about any issues.- Program an application which multiply two float array A, B and stores the results in array C (c[0]=a[0]*b[0])
- A program that gets string line(s) from the user and saves them into 10 files
- A program that creates 100 folder named from 0 to 99 concurrently
- A program that kills every other OS processes concurrently (DANGEROUS!)
Managing Threads
Well we have just done about creating and running threads, but how do we able to manage them? for example a thread should sleep (stop for a particular time) at a point, or a thread should get suspended (stop working till any resume signal), or even killing a running thread, or get the current thread with this process.Thread's Properties
Generally in every languages and platforms, threads have some common properties, for example, the thread id or private memory, threads would handled either by low-level (OS) layer, or by its runtime machineProperties
- Thread id
each thread has a unique id (int value), which is provided by either runtime or OS, this is is very helpful when you want to get the actual reference by. - Thread name
A name for the thread, it could be same through many threads, and could be null too, it's useful to categorize some threads which is not recommended. - Thread State
The current state of the thread, the state of a thread is determined by State enumeration, a thread state could be one of the following at a time- Runnable: indicates that thread is running its operation, generally when you invoke the start() thread
- New: indicates thread has created, but hasn't invoked yet, when you just create an instance of thread and don't attempt to invoke the start()
- Blocked: when thread is in running state and blocked because wants to (wait for) lock an resource which has blocked by another thread
- Waiting: when thread is sleeping for a particular time or waiting for a signal (notify)
- Timed_Waiting: when thread is waiting for a signal from any another thread within a maximum of waiting time, it means ts waits 10min for a signal, a signal could happened at 1st min, but if no any signal till 10min, thread will give up(get up) and continue its operation
- Terminated: when thread either has finished its job or killed by another thread, it means the thread has finished its job, note that a terminated thread would not start over from beginning, and it's ready for finalizing
- Interrupted: this is indicates that an interrupt signal has sent to the thread or not, note that this is not an actual state, a thread would got interrupted when it's in either running or waiting states(neither in new and terminated states). you cannot get the interrupt state by State enumeration
- Dead: when thread A is waiting for a signal from
(for example) thread B, where thread B is also in waiting mode and waits
for thread A, 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 you application in such a way that ensure there is
no any dead state would appear, note that there is not any property or
method to determine is it in dead state or not!
NOTE: in some tutorials, they explain the dead as same as terminate state, where this is okay, also dead state is also known as waiting state too, but according to my knowledge dead and terminated are two separated subjest
- Thread Priority
It indicates the priority of the thread, the higher priority causes the more process attention (context switch) for the thread, that could be one of the followings- MAX_PRIORITY
- MIN_PRIORITY
- NORM_PRIORITY (default value)
- Daemon mode: this one is used for setting that thread should run as Daemon mode or not, when a thread is in daemon mode it means, it runs until any other thread (non-daemon) are alive in the application, whenever there is no any user-thread alive, then JVM kills the daemon threads by force, you cannot even get the any exception about the exit signal, even in finally. this kind of threads are useful when your application need to have a background-service thread or a event-handler, these threads are usually run in a lower priority, once again, these threads are running within your process, but JVM does not look at them for determining your application is running or not (check the diagram). as above diagram says, whenever a user thread gets finished, JVM tests is there any user thread running yet? if there is not, then it kills every running daemon thread, so beware, don't try to change something in a daemon thread if you know it could get killed right now, it's better signal daemons before every user threads get finished, we will focus on daemon threads(examples) later, just keep reading.
Example
the following example is showing how to set and get a thread properties, it's really simple.package arash.blogger.example.thread; 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 job has finished 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, thread have some specific methods too, which some of them are belong to its thread class, some of the belong to Object class, and some of the are keywords, well the basic behavior (methods) of threads are listed below. (note that the followings are just the definition and a simple description, we will focus on them in deep)- Start: (simultaneously): when the thread need to run simultaneously with another thread(s), this operation is done by thread start() method
- Sleep: whenever a thread needs to sleep for a particular time Thread.sleep(time in ms) would help, note that there is no warranty about the exact time, it could get more , the sleep process(reminded time) could get skipped if another thread Interrupt the sleeping thread.
- Interrupt: it's used when another thread needs to
interrupt the another thread where it is in either wait (includes join()
too), sleep state, or even runnable state, for example thread A is
waiting for a signal, then thread B interrupt the thread A, here the
interrupt message contains two actions
- wakes up the target thread if it's either in wait (wait or join) or sleep state
- throws the InterruptedException to the target thread, to notify it about the interrupt signal
package arash.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 taks!\n"); } System.out.print("B: nothing interesting here!\n"); } }
As above figure says, both thread A, and B start their life at a same time, Thread A tries to do something that would take 2 sec, the thread B sleep for 3 sec, then thread A after it's first task sleeps for 10 sec, next thread B wakes up and Interrupt the thread A, please note the following when a thread is in sleep, join and wait state.- every 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 termination
- Getting the current thread: in any running thread, you would access to current thread by Thread.currentThread() method, but outside the thread you may need to check all the threads or have a references of the thread.
- Wait, Notify, Notify All: well I can say that the Most Important subject belong to threads is Synchronization between them, that this is done by Wait and Notify, we will discuss about it in detail, but if I want say it with a simple example, I would say whenever two or n threads need to synchronize with each other, a shared Object needed belong them, and now suppose that thread A has done operation 1 and has to wait for thread B to complete operation 2, here thread A after operation 1, waits for a notify signal on Object lock and after Thread B completed operation B send the notify pulse with Object lock to thread A NOTE: this is possible an Object has more than 1 thread waiting on it, when 3 thread wait on an Object they are stand on notify queue(not exactly queue, dependents on priority too), it means for next notify signal, the very first thread of the queue released, but the notify all release all the threads in the queue, we will focus on this section, just keep reading.
- Join: it means as it says, when thread A join thread B, it means thread A have to wait until thread B's operation get finished (termination)
package arash.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"); } } }
- Yield: I suggest you don't use it, use another ways instead, and what does it mean? very simple, thread says you can switch to another thread but I still need to work.
when a thread calls the yield method, then host has just got a time for
switching to another thread (if any, and if necessary, usually in same
priority), it's not as same as sleeping for 0 sec exactly, as I said,
try to use another way instead, for example, there are two running
thread with same tasks and priority and start time, and you want to try
to finish them together (at least with a small time of difference), at a
time thread A just found that it has done 10% of it's work while thread
B just 4%, here you cannot sleep for a small time even 10ms, because it
would cause that thread B gets 30%, but you could tell the host that
you can ignore my turn just now and check another thread to switch to,
but I still need to continue my work, switch back.
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, just comment the yield task and see the differencespackage arash.blogger.example.thread; public class Core { public static ThreadA threadA; public static ThreadB threadB; public static void main(String[] args) throws FileNotFoundException, 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 is going on, remember that if there are two thread that cannot sync with other, using yield() method may don't work, 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, but still work) methods here, that you need to know the differences with the new ones, and why they have mentioned as deprecated?- Suspend and Resume: the old fashion of wait and notify (synchronization), but there is a very big difference, first that Suspend pauses the thread(as well as wait does) but does not unlock any synchronized(locked) resource, and this is dangerous, because for resuming the thread you need to have the exact references, while in wait and notify you need locked object references, also when a thread locked (synchronized) object A, when it goes to wait for it, it means release it until the notify signal, after notify it acquires the lock again.
- 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, as same as interrupt) to
the target thread, and releasing all the locked resources,
like the interrupt you would catch the ThreadDeath error in a catch
block and do the alternatives, but if you don't so, then the thread get
finished even if in a infinitive( while(true){ }) loop (I don't know
why!), so just the check the following for understanding better.
package arash.blogger.example.thread; 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"); } } } } } }
as above code you are seeing, in the Mythread, Object o2 has locked, and inside the lock block an infinitive loop, it means no any thread would access it forever(like the main thread), but the stop() method causes throwing a ThreadDeath Error to the target thread which here we haven't catch it, so this error releases all of the locked objects (o, o2) by the MyThread thread, but this is possible to catch the ThreadDeath with a catch block, but note that, if you catch the error, then locked object won't get released because your thread still has the control, like the below.public class Core { 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 in lock state, and next while loop get started.
once again, try not to use these deprecated methods, however you know the differences and the behaviors, if you are planning to use them, so just keep your eye on any unexpected error and signal that would thrown.
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 and it's easy as ABC, for synchronizing two thread you need a shared Object (no primitives) and cannot be null.The lock object is usually actual Object class and called lock Object, this object(or objects) should be visible(shared) to threads want to sync with each other, thread A waits(in queue) on the lock object for the notify signal from thread B that causes thread A released from the lock and continue its work.
Notes!!!
- more than one thread would wait on an lock object, and the next notify just release one thread from the waiting queue (dependents on priority, JVM chooses)
- The notifyAll causes whole of the waiting thread get released from the queue
- When a thread in wait state, it's blocked, and have to someone send the notify signal for the rest of the work, so beware of Dead(dead-lock, infinity sleep) situation
How to Synchronize Two Thread With Each Other?
Okay now, it's doing action time, let me explain it with a simple example and the precess of the program should flow.Example
A Tick Tock application.okay now lets look closer at this application, where is the start point? how many threads? does it need synchronization? etc...
well a Tick Tock application starts with saying Tick, then 0.5 sec waiting, then saying Tock, next 0.5 sec waiting and start over, Tick, Tock, Tick, Tock,.....,
and now lets identify the processes of this one
- creating an Object lock for synchronization
- creating two thread Tick, and Tock and pass the lock object to them
- starts the threads together
- (in a for loop) Tick starts to say Tick, and 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 starts to say Tock, and 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
synchronized Block
In Java sometimes you need to lock a resource, because it needs to ensure that no any thread reads or writes on that object ,so there is locking operation is required by the required thread. it's really easy, it goes like this with synchronized block.synchronized(lock_Object){ //here no any thread would 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 now, if not, have 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 notifyingImportant Note: as we said, when a thread locks (synchronized) a resource no any thread would access to that resource, it is right, but there is an exception, if a thread waits for the locked object, then the object released from the locked until it get notified and after that get the lock for the rest of synchronized block. this situation is not with join, sleep and yield methods, just belong to wait
, if in a synchronized block, thread sleeps for 10 years, it means the synchronized object is locked for 10 years.
okay we have got everything to know to impl our example now, and what are we waiting for, check the following.
public class Core { public static Object lock=new Object(); public static void main(String[] args) throws FileNotFoundException, InterruptedException { Runnable r0=null,r1=null; Thread a,b; r0=new Tick(); r1=new Tock(); a=new Thread(r0); b=new Thread(r1); 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++){ 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? I don't think so, but always beware that wait and notify, and notifyAll need to invoked inside a synchronized block where they locked by the block.
synchronized Methods
A method is called synchronized, when that method want to locks its object (this), it looks like a method that inside itself code lock (synchronized) its object(this), so other threads should wait until method get released, please note that while a synchronized method is running, because it has locked the host object, no any thread would invoke either this or another member of the host object (this), so if a synchronized thread needs to wait, it should wait for host object(this), and here wait and notify doesn't need to surrounded by synchronized block, because synchronized method does it so.public synchronized void method(Object arg){ //it means this object will be locked by this block (method) } public void method(Object arg){ synchronized(this){ //this is same as above, but it's not recommended } }let's have a simple example
package arash.blogger.example.thread; 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 Arash M. Dehghani\n"); } }
Example
let's have the above example (tick-tock), but now synchronize threads by synchronized methods.package arash.blogger.example.thread; public class Core { public static Lock lock=new Lock(); public static void main(String[] args) throws FileNotFoundException, InterruptedException { Runnable r0=null,r1=null; Thread a,b; r0=new Tick(); r1=new Tock(); a=new Thread(r0); b=new Thread(r1); a.start(); Thread.sleep(1);//ensure that tick is going first! 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++){ System.out.print("Tick "); Core.lock.tickCycle();//notify tock, it's his turn [1] } } 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{ //synchronized method automatically lock and release this object public synchronized void tickCycle() throws InterruptedException{ Thread.sleep(500); }//there is no need for signal notify or wait for it here. public synchronized void tockCycle() throws InterruptedException{ Thread.sleep(500); } }as above example (that I recommend the previous one), we have a new member Class Lock here, that contains two synchronized method, for example in tickCycle() method, it sleeps for 500 ms, and because it's sycnhronized method, no any thread would invoke any member of this class, so the tock thread have to wait until tockCycle() member get released (Lock object in fact).
Exercises
And now, it's your turn, try to impl the following case studies, and fell free to contact me for any issue! or even verifying your impl.- Just try to extend the above example with Tick Tock Tack!
- A program that starts to write 10 large file in the hard disk with a heavy process of data(as you wish, could be combination of shifting, square, sqrt, etc...), and here a thread should displays the overall progress of the process, note that process resolution is 10%
- A graphical program (swing, awt, ...), that at the top of scree is a moving circle, and you have to hit it with your gun, your weapon shot speed you be 60 pixel per sec, user have to get the 20 scores before time runs out (2 min maybe!)
- an application that reads 1000 random generated integer from a file and just try to sort them and stores them in another file (impl an app that generates that random 1000 number first)
volatile Keyword
This keyword(feature) has added by JSE 5+, generally they added it for multi-threaded applications, and what does it do? in a multi-thread system, this is possible that two thread wants to set or get a value of a variable at a time, so here inconsistency would appear, for example two threads, one of them is updating value i, and another one wants to read value i, it is possible that second thread reads the old value, so there is no warranty that force the second thread to read the new value, except get it via a method and lock it by synchronized keyword (single thread approach). here if a field being volatile, it means the reading or setting(no read-modify set) threads ensure that they are reading and setting the very last value of the variable. this is not recommended for read-modify (like i++, i=i>>2, i*=2) changes, because volatile does not lock the object, the volatile is really help full when there are some threads updating value, simultaneously a thread needs to read the value(like an auction system), volatile ensures that the reading thread will get the very last update, it waits the thread until another update threads get finished. And now when should we use volatile? and when should use synchronized block instead?- If thread needs to just read a value, and you want ensure them about the latest updated value, use volatile
- If thread attempts to update a value without need to know about the current value (like i=10, i='A', i=1.990E4D), use volatile
- If thread attempts to update a value and the update dependents to current value (like i=i+1, i%=7, i=1.994E4D-i*2), use synchronized thread
How to Set a Variable Volatile?
so this is really easy, just set as volatile with variable's declaration, like the above.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 waits for the last update, then return the updated value. } }
Example
Now lets have some example, decide either volatile or synchronized approach would help for each one.Last User logged on
here this is an application that would track (set and get) the last user id has logged into the system, impl the desired system.and now we have to analysis that would this multi-thread? so yes of course, because the data (last user id) would get updated and read from different systems and requests concurrently.
Okay, first as it mentioned the user id gets updated to a new value, and it doesn't dependent to the old value, so here the volatile approach would help within setting and getting value, so the code would be like this.
public class SysMgr{ private volatile String lastUserId=null; public void set(String lui){ this.lastUserId=lui; } public String get(){ return this.lastUserId;} }in above code, if a thread(A) wants to get the lastUserId value, and simultaneously another thread(B) is updating it, then the thread A will waited 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 login have.here this example is a bit same as the previous example, except, when you want to count, you want to update an exist value, in fact, update process is read-modify, it dependence to the current value, so hear volatile would not help, because id does not lock the variable, but for reading is okay, then the code would be like this, variable definition will be volatile for readers, 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++;}//because this method is synchronized, maximum of 1 runnable is exist public long getValue(){return this.logins;}//the variable logins is volatile, so it ensures the very last update value public void reset(){this.logins=0;}//it could be without locking, because variable is volatile /* * some private members */ }as above code shows, the getValue() is not synchronized, and this is not required, because at any reading value by this method, you ensures that the committed(new) value will be returned because of volatile declaration of variable logins, but note that getValue() method should be synchronized if logins variable was not volatile, because it is possible some private members would update it in separated thread(like reset method), and this will cause the inconsistency.
Relative and Absolute Update
here we are going for an application that would update a variable directly (modify only) or increment it by one (read-modify).well this is going be easy, we could separated the these two tasks into two synchronized, and non-synchronized methods.
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 }Well you have not focus like this in your application, if this is not going be a large project, but you have to well known about the differences, when lock and when volatile, and when both!
Notes
Okay Okay Okay, I would say, now you can write any multi-thread application by your hand, but there are still some important things that you need to know about like patterns, issues, managements and even how to make a coffee after this tutorial.Main Thread
if your application contains a main method, then JVM create a method called main, and run the your main method with this thread.Creating Thread
In Java there are two ways for creating (declaring) a method as thread, Implementing Runnable interface or extending Thread class, which the first ways is more common. like the belowclass MyThread implements Runnable{//recommended @Override public void run() {} } class MyThread2 extends Thread{ @Override public void run() {} }
Daemon Threads
as we mentioned, there is two kind(by the running method) of thread in java, user-threads, and daemon-threads, as we mentioned, JVM remove whole of your application when there is no any user-thread running, and just kill daemon-threads silently, so please beware about the daemon-threads, do not change something if you know application could finished right away, because daemon thread would not receive any interrupted or thread death signal. either do not change any thing within these threads, or signal them implicitly before your user threads get terminated, just check the code below.package arash.blogger.example.thread; 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!\n"); } } class MyThread implements Runnable { long res = 1L; @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; System.out.print("Res right a way: " + res + "\n"); } } catch (Exception | ThreadDeath e) {// catch for any stop() or interrupt() signal System.out.print("I will never get any signal by JVM :(\n"); } } } } }as above code says, the MyThread has set as a daemon mode, and note that you have to set at as daemon before you start it, MyThread has a for loop that would take 10 sec, 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 not any clear method for shutting down a thread, so you cannot force a user-thread to shutdown, well you have to design a way to determine that the Thread should stop working, one of them is using interrupt() method and interrupted state of the thread, this is not recommended, because interrupt has designed for waking up a thread where in either sleep, join, or wait state, please note the following when you are invoking interrupt method, it could have different behaviors.- if thread is in either wait, join or sleep state, then the rest of the sleep/wait state omitted and an InterruptedException sent to the thread, and doesn't set the interrupted flag to true
- if thread is blocked by IO operation (reading file, stream, ...), then the rest of the sleep/wait state omitted, the IO channel get closed and a ClosedByInterruptException sent to the thread, and doesn't set the interrupted flag to true
- if thread is in runnable state, then just set the interrupted flag to true (we can use it as shutdown signal)
- if thread is in new state(haven't started yet), then nothing to get happened!
package arash.blogger.example.thread; 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 shutdown signal haven'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"); } }here in above code, as you see MyThread continue its work until another thread set its interrupted flag to true, it means stop working, note that in MyThread there is no any try catch, because as we mentioned, if thread is in running state, just its interrupted flag set to true(no any exception, not same for stop() method!).
while the above code works without any problem, but this is recommended use an implicit way to signaling a thread to stop its working, that I would impl it like this.
package arash.blogger.example.thread; 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);// wain 10 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 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 havn'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 one of the 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 notify(either notify, stop or interrupt) it, then after notify it tries to acquire the lock again, because it lost the lock before gone in wait state.
sleep()
id doesn't release any locked object(any), and sleeps for a specified amount of time, it could get canceled(wake up) by either stop or interrupt signals.
but here we could wait (wait(max_of_wait_time)) for a notify signal, but with a maximum of time. it means thread releases the locked object and waits for notify signal, and it will notify itself if no any thread notify it by wait time.
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 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 that wait(1000) except sleeping for 1000 sec, releases the locked object too. I've seen in some tutorial they mentioned that try to use wait instead of sleep, I don't say it, now you know the differences.
Switching Between Threads (Untruthful 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, and it has to switch to another thread and does some task of that thread too, and so how do we see everything smooth? because our CPU is really powerful, its 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 want to do it explicitly(in-direct). okay we have know enough about wait and notify, we use this method when even one step of a thread is important for us, for example should run this step after this step or not. the following diagram is showing possible thread switching between two un-synchronized(independent) threads, but note that it's even possible CPU completes whole of the thread one then starts with thread two, or does 1% of thread 1, switch to thread 2 and does it 100%, then switch back to thread 1 and completes the thread 1. well as you see there is no warranty that ensure 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(force switch) to another thread? we have mentioned about yield() method, but as I said do not trust yield() method, because this method calls underlying(OS) functions that skip this one, switch to others, but sometimes you see no any differences. for example just check this example out.
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, I even got this result (whole thread 1, whole thread 2, and then main thread).
okay now let's have a use case, in the above code, we want to try 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. for example check the new threads methods
class MyThread implements Runnable { @Override public void run() { Thread.yield();//tells host 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 users try not to use it, but here what should we do? sometimes you are walking with your dog, you tell him stop me for a while(yield() method), and you see no differences!, no responses!, then you try to do it yourself, you stop yourself for a bit, then another thread would get switched, here you stop yourself for a very small of time (even less than 1 ms), so except calling yield() method (if doesn't work) why not sleeping for a bit!? so our new code would be like this
package arash.blogger.example.thread; 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 you don'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 replace the yield method with sleeping for 50 nano seconds! but still I'm not sure that main thread sentence [S] goes first, just run the above code, 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.
please note that it dependents on your CPU too, if your CPU is strong enough then 50 nano seconds is good enough to switch to another, but another CPU may needs more!
Advanced Topics
There is no room for low-performance, so let's talk professionally, here we want to talk about advanced topics.Manage Your Memory
Each thread has a private memory which is accessible to its components (methods, classes, etc...), and a shared memory which is belong to every thread, please note that these resources (memory) would get 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), so beware of creating to much threads, it would eat whole of your memory very easy. executing a sequential(serial, single-thread) application is more more more easier than a multi-thread application for the CPU, while you are able to run your application by GPU (with restricted functionality). now just run the following code to see yourself how many threads would disturb your system, and watch your system memory and performancepackage arash.blogger.example.thread; 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: if you ask me, and other guys who know multi-thread programming, we say 5000 thread in an application is not a dragon killing story(as you feel), 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 in future you have to separate your application into concurrent and serial modules (execution flow), and separate the code between GPU and CPU (not so hard, keep cool).
Semaphore, Limiting Maximum of Running Threads
Well one of the patterns which causes limit the maximum of running thread is called (Semaphore), this is very useful to prevent your application of running to much threads that would causes memory and process(execution-time) issues, here semaphore ensures you there are will not more than n maximum thread of running, this is useful when you application is small (not recommended for big applications), so I would say this may be necessary but not perfect!There is a good implemented semaphore class available in its Java SE API, but I suggest you do it yourself, if you want to know what a semaphore really does!?
for having a semaphore, you have to know what does it do exactly, well semaphore looks like a execution permission system, at time t0 you want to run a thread, so first you have to get the permission of semaphore, here semaphore tracks every running thread and decides to either approves, blocks or rejects you. this is going to be easy. the above semaphore tracks the running thread (in-direct) with counting, note that here client have to signal semaphore again and tells it that has finished it's work, then a value removed by the running threads. this kind of semaphore is known as counting semaphore, and now let's have a simple impl of this one.
package arash.blogger.example.thread; 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 the permission to run a thread [1] new Thread(new MyThread(sem,i)).start(); //runs the thread [3] } Thread.sleep(100); System.out.print("Completed :)\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 get 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 that it has finished its job [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){ this.wait();//checks is it possible to run a thread at this time? //or should wait until another thread get finished [2] } runningThreadSize++; } public synchronized void release(){ runningThreadSize--;//decrease one thread from runningThreadSize try{ this.notify();//notify any waiting thread (if any) [5] }catch(IllegalMonitorStateException e){ //if no any thread were not waiting for this, then this block get caught } } }the above example is about running 300 thread, that this is not a good idea run every 300 threads at a time, we want to limit it(at a time) with semaphore, here the main thread gets permission for each 300 thread wants to run, and semaphore have to decide to either wait or approve the request, if maximum of threads are running, then the semaphore blocks until one of the threads(running threads) get terminated and signal 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 main thread instead of block it.
Recyclable Threads (Thread Pool)
As we mentioned, a thread has some properties(takes some memory), but there is one important thing belong them, OS and JVM doesn't care about what's going on (execution flow) in a thread, they know just that this thread should get run, this is like a postman, it brings every envelop to its destination and doesn't care what is inside, then the envelop packet get destroyed, and a new packet should get used for the new one, so here its time-consuming about destroying and creating a new packet, all want I say that, why don't use the old packet for the next envelop too? or why don't use the existing thread for the next thread 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 independent to any business flow, a thread should be a thread, not my business!.
Well this could be done very easy by changing the impl of your application, also you need to impl a module which controls these threads and execution flows, it could be like this. as above figure says, a thread is got from the thread pool, it does something and has to back to the pool for the next request. so here the thread object should independent of any business, that is really easy to solve, when we pass the business as a interface to the thread, like this.
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 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 } }
and let's have some detail too
//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, that should get 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 until this thread gets a job} tf.run();//runs the client business code this.sendFinSignal(); } } private void sendFinSignal(){ //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; this.thisThread.interrupt();//interrupt the current thread } } //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 can understand UML, very simple.(feel free to contact me, if you have issue with anything, I will explain of course.) now let me explain the above diagram, well this is a UML class diagram, it shows 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, so let's have a closer look to them, what are they for?
ThreadFace
this interface is used as a bridge between actual thread and the virtual thread, here virtual thread points to a method that should get run as a thread, but it(ThreadFace) is not a real thread(Runnable), well it will get run by the real thread in Runner class, it contains a void method which does not accept any argument, as same as actual Runnable interface, in fact the actual thread will run the ThreadFace's run method
interface ThreadFace{ public void run();//looks like the Runnable, but could be in another face too }
ThreadPool
this interface is used for communication between client and thread pool, client needs to pass ThreadFace's (implementation) instance to the ThreadPool, and then actual ThreadPool (ThreadPoolImpl) has a decision to either runs or waits the client until a new ready thread. as the previous diagram says, client sends its request (by ThreadFace) to the ThreadPool (ThreadPoolImpl), and if there is an idle thread available, then thread will run, but if is not, then client has to wait (blocked by pool) until a thread finishes its job and returns to the pool and does the client job. also because of actual threads (Runner) are immortal(in a true while loop) so this interface provides another method for shutting down every threads.
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 acquaints the thread pool with this interface that its job has finished and is ready to back to the pool
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 have communication with ThreadPoolComm and ThreadFace interfaces, inside the run method it runs the ThreadFace interface passed by ThreadPoolImpl class, so because it runs a interface, it could be anything, it could have any implementation. this class get run its thread (run) by the ThreadPool, and waits for a signal for the very next ThreadFace object, after it notified by pool, it runs the ThreadFace's runs method and signals the pool to head back to the thread pool again for the next request, this class is hand of our thread pool application.
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 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 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(){//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] } }you can another semaphore example here
ThreadPoolImpl
if Runner class is the hand of the application, then ThreadPoolImpl is the heart of our application, 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 too, it also sends the shutdown signal to every running/ready threads. whenever a client needs to run its ThreadFace, this class checks is there any ready thread or not? if yes, then pass the ThreadFace object to the Runner object and job get started, if no, then it blocks the client until a running thread(Runner) finishes its job and heads back to the pool, then pass it to it. this class contains two list of Runner class, readyPool and runningPool, first one contains idle(ready) threads that are ready for action, and second one contains threads that are doing something(busy). there is a note belong to this class, when we use thread pool, we want to limit the maximum running thread at a time, and also recycle the threads too, so there is only one instance of this class is required, for this we hide the constructor, so no one would create one, but we need at least one, it could be done by one static ThreadPoolImpl instance, in fact this class, itself creates one instance of itself and stores inside, and clients would get this instance by a static method and work with it, this is a simple pattern, called Singleton, very useful!
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 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] try{ this.notify();//notify waiting thread(if any) that a ready thread is available [0=8] }catch(Exception e){} } @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. note that a client should implements the ThreadFace, so we could call it our client.
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(); } } }
talking is enough, let's have a look to the whole code!
package arash.blogger.example.thread; 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] try { this.notify();// notify waiting thread(if any) that a ready thread is // available [0=8] } catch (Exception e) { } } @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 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 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() {// 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, and monitor your system, the above code runs very fast, because 32 threads for CPU is not to much hard to execute (at least better than 5000 at the same time), also the most important thing is that a thread gets used many times, there is no time needed to destroying and creating threads for every thread and this is the main advantage over semaphore, and here is another example in thread pool.
well I'm planning to writing another article about java threading(this one is big enough almost) but in advance, also mention about high performance computing(HPC) in java too, so if you found this article good enough, just keep tight with updates. also you can find another example here and once again, for any issues, questions, problems, just feel free to contact me :D.
No comments:
Post a Comment