Vous êtes sur la page 1sur 16

How to Java Threads juza – iamjuza[at]gmail[dot]com

How to Java Threads

Introduction
Hello every one, this is my new article, and it's about the threading world in java programing language. I
start programming java since a while, and one of the most important things in programming is threads,
with them, you can execute almost simultaneous all kinds of things, making the program much faster
them programing without them (cutting in the dead times), example, if you can read to files in the same
time, why you read them one by one ? Threading is the answer, so let's learn something...

The Basics
After we start programming we should get some knowledge about process and threads.
A program is basically a collection of lines of code previously compiled and executed by the CPU.
The CPU can run multiple process 'each time' (cpu only process a task each time), switching between
tasks (time-sharing), this is called multitasking.
“... a process is an instance of a computer program that is being executed. It contains the program code
and its current activity. Depending on the operating system (OS), a process may be made up of multiple
threads of execution that execute instructions concurrently.”
In a multitasking environment, process must assume several states.

The image above represents the process live cycle. I will make several references for this image
throughout this paper.
A task is a set of program instructions that are loaded in memory.
A process can have several threads that are execute in the 'same time', threads can be considered as
sub-process that run in a process father. This kind of environment is called multi-threading.

The image above represents threads life cycle.

1
How to Java Threads juza – iamjuza[at]gmail[dot]com

The Concepts
In all OS you have process that ran in memory, those process have there own resources and each one of
them is controlled by the OS.
One process have one or more threads that can be manipulated by the OS or by the process. Threads
have less processing time in the OS that process have.

In java you have always one thread (main), with gui applications you have one more thread.

In java you have two ways to implement threads:

● Making a subclass of the java.lang.Thread;

● implement java.lang.Runnable interface.

In the two of them, you must have the "public void run() {}" method, this method is executed every time
a thread starts, so it's the 'brains' of the thing.

public class Main {


public static void main(String[] args) {
FirstThread ft = new FirstThread(1, 10);

ft.start(); //start the thread


}
}

class FirstThread extends Thread {

private int min;


private int max;

public FirstThread(int min, int max) {


this.min = min;
this.max = max;
}

public void run() {


for (int i = min; i<max; i++)
System.out.print(i + " ");
}

}
1 2 3 4 5 6 7 8 9

So this is the very basics of threads programing, the program runs a loop printing all the numbers
between the 'min' and 'max' these variables declared in the "FirstThread" class passed to constructor.

You should never call the run() method directly. If you do that you just execute run() in the very single
thread that was running when run() method was called.

public class Main {


public static void main(String[] args) {
FirstRunner fr = new FirstRunner(1, 10);

Thread t1 = new Thread(fr, "firstrunner"); // add names to the threads

2
How to Java Threads juza – iamjuza[at]gmail[dot]com

t1.start(); //start the thread


}
}

class FirstRunner implements Runnable {

private int min;


private int max;

public FirstRunner(int min, int max) {


this.min = min;
this.max = max;
}

public void run() {


for (int i = min; i<max; i++)
System.out.print(i + " ");
}

}
1 2 3 4 5 6 7 8 9

When a thread is dead, you can't bring that to life, you just have to replace the dead thread with a new
one. But, dead thread still exists, set the dead thread reference to null, so the garbage collector can
destroy it.

The stop() method kill the thread immediately. But isn't a good policy, the stop() method of the Thread
class has been deprecated which means it will disappear from future versions of Java.

By seeing this two examples you will ask yourself "Threads vs Runnable" what's the difference?

An instance of Thread uses the run() method of a Runnable class.


A class extends Thread and overrides the run() method.

OK, sun created two different ways to build threads, one of them is by extending and the other is by
implementing, so if you want just a thread that you want use Thread, but if you want something else you
should use the implementation method.
Java only has single inheritance, so if you want that, your class subclass other class you can't do it!

The result of those examples aren't platform independent:

● Depending how you OS implement multi-threading;


● Depending of the JVM and OS.

There are two types of multi-threading:

● Cooperative
○ Every thread interact with each other in order, that all of them can be executed with an order.

● Pre-emptive
○ Controls the threads and compels them to yield it the execution time assuring that all threads
are executed.

Java doesn't imposes none of these types.

Depending of the multi-threading time the execution results are different.

Let's see what an example with this two types of multi-threading.

3
How to Java Threads juza – iamjuza[at]gmail[dot]com

public class Main {


public static void main(String[] args) {
Runner r1 = new Runner(1);
Runner r2 = new Runner(-1);

Thread t1 = new Thread(r1, "First Thread");


Thread t2 = new Thread(r2, "Second Thread");
// Start threads
t1.start();
t2.start();
}
}

class Runner implements Runnable {


int max = 10;
String str;

Runner(int m) {
if (m < 0)
str = "-";
else
str = "+";
}

public void run() {


for (int i = 0; i < max; i++)
System.out.print(str + i + " ");
}
}

+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 -0 -1 -2 -3 -4 -5 -6 -7 -8 -9

This happens because the first thread (t1) don't transfer the execution to the second thread (t2).
Let's see how this can be done using the method sleep, this will t1 sleeping and will make t2 runnable,
let's see the example above.

public class Main {


public static void main(String[] args) {
CoopThread t1 = new CoopThread(1);
CoopThread t2 = new CoopThread(-1);

t1.start();
t2.start();
}
}

class CoopThread extends Thread {


int max = 10;
String str;

CoopThread(int m) {
if (m < 0)
str = "-";
else
str = "+";
}

public void run() {


for (int i = 0; i < max; i++) {
System.out.print(str + i + " ");
if (i % 2 == 0)

4
How to Java Threads juza – iamjuza[at]gmail[dot]com

try {
this.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

+0 -0 +1 +2 -1 -2 +3 +4 -3 -4 +5 -5 -6 +6 -7 +7 +8 -8 +9 -9

Why not use yield? The yield is a method used to a thread give up the control only for the same priority
level. In these cases a thread that has a lowest priority may never be executed, this kind of environment
is called starvation.

yield vs sleep, the biggest difference between this two is the fact that when you use the yield method,
you pass the control to other thread, but this thread will stay in running mode, so making the thread that
passes the control trying to recover it again. When you use the sleep method, the thread will pass to the
sleeping mode, making that lower priority threads can be executed.

public class Main {

public static void main(String[] args) {


SleepThread t1 = new SleepThread(1);
SleepThread t2 = new SleepThread(-1);

Thread eu = Thread.currentThread();
int p = eu.getPriority();

t1.setPriority(p - 1);
t2.setPriority(p + 1);

t1.start();
t2.start();
}

class SleepThread extends Thread {


int max = 10;
String str;

public SleepThread(int m) {
if (m < 0)
str = "-";
else
str = "+";
}

public void run() {


for (int i = 1; i < max; i++) {
System.out.print(str + i + " ");
if (i % 2 == 0) {
try {
sleep(100);
} catch (InterruptedException e) {
}
}
}
}
}

5
How to Java Threads juza – iamjuza[at]gmail[dot]com

+1 +2 -1 -2 +3 +4 -3 -4 +5 +6 -5 -6 +7 +8 -7 -8 +9 -9

So, for conclusion we can assume that using the sleep method should make the process less efficient,
because you have to wait 100 milliseconds for start the thread again. Using the yield method could lead
to starvation (There is always a thread with the lowest priority running in with you application, this thread
run in the JVM, and it's called garbage collector).

So you should plan your software very careful.

We talked about how threads exchange the processing time, now, we will talk about how threads share
data between them.

So let's go share some objects!

6
How to Java Threads juza – iamjuza[at]gmail[dot]com

Sharing objects between threads


public class Main {

public static void main(String[] args) {


Something something = new Something();

SleepThread t1 = new SleepThread(something, "1");


SleepThread t2 = new SleepThread(something, "2");

t1.start();
t2.start();
}

class Something {
String str;

public String getStr() {


return str;
}

public void setStr(String str) {


this.str = str;
}

class SleepThread extends Thread {

String str;
Something something;

public SleepThread(Something something, String str) {


this.something = something;
this.str = str;
}

public void run() {


for (int i = 1; i < 10; i++) {
something.setStr(this.str);
System.out.print( something.getStr() + " ");
if (i % 2 == 0) {
try {
sleep(100);
} catch (InterruptedException e) {
}
}
}
}
}

112211222112112212

Output with hashcodes


1 19770577 1 19770577 2 19770577 2 19770577 1 19770577 1 19770577 2 19770577 2 19770577
1 19770577 1 19770577 2 19770577 2 19770577 1 19770577 1 19770577 2 19770577 2 19770577

7
How to Java Threads juza – iamjuza[at]gmail[dot]com

1 19770577 2 19770577

As you can see, the objects are the same.

Ok, there's a problem, witch is the atomic concept. A instruction is atomic when it can not be interrupted.
If we have used numeric values (long and double) in the example above, we ran the risk that statements
were not be executed.

public class Main {

public static void main(String[] args) {


Something something = new Something();

SleepThread t1 = new SleepThread(something, 1);


SleepThread t2 = new SleepThread(something, 2);

t1.start();
t2.start();
}

class Something {
double val;

public double getVal() {


return val;
}

public void setVal(double val) {


this.val = val;
}

class SleepThread extends Thread {

double val;
Something something;

public SleepThread(Something something, double val) {


this.something = something;
this.val = val;
}

public void run() {


for (int i = 1; i < 10; i++) {
something.setVal(this.val);
System.out.print( something.getVal() + " ");
if (i % 2 == 0) {
try {
sleep(100);
} catch (InterruptedException e) {
}
}
}
}
}
2.0 1.0 2.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 1.0 1.0 2.0 1.0 1.0 2.0 1.0
1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 2.0
1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 2.0 2.0 1.0 1.0 1.0 2.0

8
How to Java Threads juza – iamjuza[at]gmail[dot]com

Like you see above, the outputs are not equal, so we have to make sure that this kind of environment
doesn't happen. This could be done by setting a method with the atomic attribute witch is 'synchronized'.

Let's see the example.

public class Main {

public static void main(String[] args) {


Something something = new Something();

SleepThread t1 = new SleepThread(something, 1);


SleepThread t2 = new SleepThread(something, 2);

t1.start();
t2.start();

class Something {
double val;

synchronized public double getVal() {


return val;
}

synchronized public void setVal(double val) {


this.val = val;
}

class SleepThread extends Thread {

double val;
Something something;

public SleepThread(Something something, double val) {


this.something = something;
this.val = val;
}

public void run() {


for (int i = 1; i < 10; i++) {
something.setVal(this.val);
System.out.print( something.getVal() + " ");
if (i % 2 == 0) {
try {
sleep(100);
} catch (InterruptedException e) {
}
}
}
}
}
1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 2.0

9
How to Java Threads juza – iamjuza[at]gmail[dot]com

Ok, we have just resolved our problem, but you should not use the synchronized attribute everywhere
because:

● This attribute could make applications slower;

● Could case deadlock.

A deadlock is a common problem in multiprocessing where many processes share a specific type of
mutually exclusive resource known as a software lock.
A object that uses in is methods the synchronized attribute is called object monitor.
When a thread access to a shared object, that thread acquires the lock of that object, in other words,
when that thread access to that object only when that thread leaves that object, is when another thread
can access the object again. This kind of environment only happens when you have the synchronized
attribute in your methods, when you don't have, every thread can access to the object in the same time.
Imagining the following environment. If we have two threads consulting a value constantly...

public class Main {

public static void main(String[] args) {


Something something = new Something();

SleepThread t1 = new SleepThread(something);


SleepThread t2 = new SleepThread(something);

t1.start();
t2.start();

class Something {
boolean val;

synchronized public boolean getVal() {


return val;
}

synchronized public void setVal(boolean val) {


this.val = val;
}
}

class SleepThread extends Thread {

Something something;

public SleepThread(Something something) {


this.something = something;
}

public void run() {


while(true) {
...
if (something.getVal())
something.setVal(!something.getVal());
else
something.setVal(!something.getVal());
...

10
How to Java Threads juza – iamjuza[at]gmail[dot]com

}
}
}

There is a problem in the example above, let's think. In the run method we use the getVar method to grab
the variable value, however we use it twice, and the method run is doesn't have the synchronized
attribute, so, we run the risk that that value (var) could be altered in the process, this kind of problem is
called race-hazzard.
To make sure all the process run in a 'natural' way, we have to lock this area, making this way that any
other thread access this area, we don't do that by declaring the run method with the synchronized
attribute, because it will cause the starvation problem. We will declare a critical section in the run method
to solve this problem.

public class Main {

public static void main(String[] args) {


Something something = new Something();

SleepThread t1 = new SleepThread(something);


SleepThread t2 = new SleepThread(something);

t1.start();
t2.start();

class Something {
boolean val;

synchronized public boolean getVal() {


return val;
}

synchronized public void setVal(boolean val) {


this.val = val;
}
}

class SleepThread extends Thread {

Something something;

public SleepThread(Something something) {


this.something = something;
}

public void run() {


while(true) {
...
synchronized (something) {
if (something.getVal())
something.setVal(!something.getVal());
else
something.setVal(!something.getVal());
}
...
}
}
}

11
How to Java Threads juza – iamjuza[at]gmail[dot]com

We will declare the synchronized block with the variable we want to lock, like you see in the example
above.
For conclusion we have two ways to set a lock in a object:
● Declaring the synchronized attribute in the methods.
● Using critical section with the synchronized block, this way locking the object we want.

12
How to Java Threads juza – iamjuza[at]gmail[dot]com

Thread colaboration

Ok, we had solved all problems inherent to share objects between threads, it's time to make them coper.
Let's study a comun case, a thread fetch data, and other thread process that information.
In the next example we will have a thread that stores data, and other thread reads that data. We will
implement a mechanism that prevents that thread stores data in the buffer if this one is full, and the
same with the thread that read the buffer, making this one read data only if the is something to read.

public class Main {

public static void main(String[] args) {


Something something = new Something();

Reader reader = new Reader(something);


Writer writer = new Writer(something);

reader.start();
writer.start();

class Something {
String val;
boolean empty = true;

synchronized public String getVal() {


this.empty = true;
return val;
}

synchronized public void setVal(String val) {


this.val = val;
empty = false;
}

public boolean isEmpty() {


return this.empty;
}

class Reader extends Thread {


Something something;

public Reader(Something something) {


this.something = something;
}

public void run() {


while (true) {
while(something.isEmpty()) {
System.out.println("Reader - Buffer is empty!");
try {this.sleep(100); }
catch (InterruptedException e) {}
}

13
How to Java Threads juza – iamjuza[at]gmail[dot]com

System.out.println(something.getVal());
}
}
}

class Writer extends Thread {

Something something;

public Writer(Something something) {


this.something = something;
}

public void run() {


while (true) {
while(!something.isEmpty()) {
System.out.println("Writer - Buffer is full!");
try {this.sleep(100); }
catch (InterruptedException e) {}
}
something.setVal("Hello World!");
}
}
}

...
Reader - Buffer is empty!
Writer - Buffer is full!
Writer - Buffer is full!
Hello World!
Reader - Buffer is empty!
Writer - Buffer is full!
Hello World!
...

As you see in the example above, the threads work together!


But we have a problem here, the example above uses too much CPU, and we can't actually expect the
application executes the code without any problems, as you see in the output log, sometimes the writer
does not have something to write and the reader does not always have something to read.
But all this can be resolved using the notify() and wait() methods, Like this...

public class Main {

public static void main(String[] args) {


Something something = new Something();

Reader reader = new Reader(something);


Writer writer = new Writer(something);

reader.start();
writer.start();

class Something {
String val;
boolean empty = true;

14
How to Java Threads juza – iamjuza[at]gmail[dot]com

synchronized public String getVal() {

if (this.empty == false) {
try { this.wait(); }
catch (InterruptedException e) {}
}

notify();

this.empty = true;
return val;

synchronized public void setVal(String val) {

if (this.empty) {
try { this.wait(); }
catch (InterruptedException e) {}
}

this.val = val;
empty = false;

notify();

public boolean isEmpty() {


return this.empty;
}

class Reader extends Thread {


Something something;

public Reader(Something something) {


this.something = something;
}

public void run() {


while (true) {
System.out.println(something.getVal());
}
}
}

class Writer extends Thread {

Something something;

public Writer(Something something) {


this.something = something;
}

public void run() {


while (true) {
something.setVal("Hello World!");
}
}
}

15
How to Java Threads juza – iamjuza[at]gmail[dot]com

Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

wait() Causes current thread to wait until another thread invokes the notify() method or the
notifyAll() method for this object.
notify() Wakes up a single thread that is waiting on this object's monitor.

As you see, using the notify() and the wait() methods we don't need to wait for the threads read or write,
because when the writer writes into the buffer it will wait for the notification of the reader thread, the
reader thread will print the message (“Hello World!”), and will notify the writer thread. The reader will wait
for being notified by the writer to print something.

Conclusion

The use of threads is extremely import by increasing drastically the performance of the applications.
I hope you have learn something!

References
[1] http://en.wikipedia.org/
[2] http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html
[3] http://www.coderanch.com/t/233370/Threads-Synchronization/java/Thread-vs-Runnable
[4] http://www.javaworld.com/javaworld/jw-04-1996/jw-04-threads.html
[5] http://www.codestyle.org/java/faq-Threads.shtml
[6] http://java.sun.com/docs/books/jls/second_edition/html/memory.doc.html
[7] http://java.sun.com/j2se/1.3/docs/api/java/lang/Thread.html
[8] http://72.5.124.55/j2se/1.4.2/docs/api/java/lang/Object.html

16

Vous aimerez peut-être aussi