Date post: | 19-Jan-2016 |
Category: |
Documents |
Upload: | juliana-kristina-hill |
View: | 217 times |
Download: | 1 times |
Li Tak SingLecture 2
COMPS311F
1
ThreadsA thread is a single sequential flow of
control within a program.Many programming languages only allow
you to write programs with only one thread. In other words, these single threaded programs would only do one thing at a time.
A program with many threads would be one that can do many things at the same time. For example, it can read a file, do some calculation at the same time.
2
ThreadsWhen you run a Java program, a thread is
used to execute statements in the main method.
3
ThreadsHowever, there are other threads that you
may not aware. For example, if your program has a button
and you have added an ActionListener, then there is a thread that is going to execute some statements when you press the button.
4
ThreadsIn all Java programs, there is a thread to
collect garbage. So although you think that you are writing
a single threaded Java program, there are more than one thread in it.
5
Life cycle of a thread
6
ThreadSome threads are created by the Java
runtime system. For example, the garbage collection thread, the thread that executes the statements of the main method, the thread that handle listeners.
However, you can also create your own threads.
7
ThreadsThread is a Java class that represents a
thread. When you create a thread using the
statement:
Thread thread=new Thread();
it enter the Born state in the last figure.
8
ThreadWhen the start method of a thread is
invoked, it enters the Ready state. When a CPU is assigned to the Thread, it
enters the Running state and the statements defined in the run method of the thread would be executed.
When the time allocated for the thread has finished, the thread goes back to Ready state.
9
ThreadWhen the static sleep method of Thread is
executed, the current thread would go to the Sleep state and the CPU would stop executing the statements in the run method.
When the prescribed time for stopping has expired, the thread would go back to the ready state.
10
ThreadWhen the thread is executing the wait
method of an object, it enters the wait state and it will stop execution.
When some other threads invoke the notify or notifyAll method of the object, the thread may go back to the ready state.
11
ThreadWhen the thread is trying to do some IO
but is blocked, it enter the Blocked state.When the IO is finally finished, it goes back
to the ready state again.When the thread has finished executing all
the statements in the run method, it enters the Death state.
12
Methods of Threadpublic void run(): The statements in this
method would be executed when the thread is in the Running state. You would not invoke this method directly. The method would be invoked when you invoke the start method. The original run() method of Thread contains nothing. So you need to override this method to whatever you want this thread to do for you.
13
Methods of Threadpublic void start(): This method is used to
change a thread from the Born state to the Ready state. Then, if a CPU is available, the statements in the run() method would be executed.
14
public class TestThread extends Thread {
/** Creates a new instance of TestThread */
public void run() {
for (int i=0;i<10;i++) {
double sum=0;
for (int j=0;j<1000;j++) {
for (int k=0;k<1000;k++) {
sum+=Math.sin(i+j+k);
}
}
System.out.println("thread: "+sum);
}
}
15
public static void main(String st[]) {
TestThread aThread=new TestThread();
//thread enters the Born state
aThread.start(); //thread enters the Ready state.
for (int i=0;i<10;i++) {
double sum=0;
for (int j=0;j<1000;j++) {
for (int k=0;k<1000;k++) {
sum+=Math.sin(i+j+k);
}
}
System.out.println("main: "+sum);
}
}
}
16
main: -0.025189987251292567
thread: -0.025189987251292567
main: 0.7871690307421841
main: 0.8758084720864001
thread: 0.7871690307421841
main: 0.15923364319459674
thread: 0.8758084720864001
main: -0.7037398629077654
main: -0.9196981845149624
thread: 0.15923364319459674
main: -0.29009023668378703
main: 0.6062253369356854
thread: -0.7037398629077654
main: 0.9451801315255973
thread: -0.9196981845149624
main: 0.41514067211553857
thread: -0.29009023668378703
thread: 0.6062253369356854
thread: 0.9451801315255973
thread: 0.41514067211553857
17
ThreadInteresting observations in last program:
the run method has never been called in the program. However, we can see that the statements in the run method have been executed.
the statements in the run method are interleaved with statements in the main method. It is a proof that there are two flows of control, or two threads.
18
currentThreadIn last example, you actually encountered
two threads, one is created by the programmer and is called aThread in the program. The other thread is the thread that executes the statements in the main method, it has no name.
19
currentThreadSince you have the reference aThread
refers to the first thread, you can do whatever you want to aThread directly. However, how can you do something about the thread that executes the main method? The answer is the static method currentThread of Thread.
20
currentThreadIn anywhere in your program, if you
execute the statement:
Thread cThread=Thread.currentThread();
then cThread refers to the thread that is currently executing this statement.
21
sleepsleep is a static method of Thread. When
you execute this method, the current thread would go to sleep for certain period.
The method is a static method which means that you can only ask yourself to sleep, not others.
22
sleep
Now, assume that threadA is executing the statement threadB.sleep(1000) and threadB is executing the print statement.
threadA:
.....
threadB.sleep(1000);
......
threadB:.....System.out.printf("abcd");.....
23
sleepWhich thread would go to sleep? Although
we have executed the sleep statement in the form: threadB.sleep(1000);However, sleep is a static method, therefore it will not affect threadB. In fact, this method will only affect the current thread. Now, this statement is executed by threadA, therefore it is threadA that is going to sleep, not threadB.
24
sleepSo actually, the statement:
threadB.sleep(1000);is better replaced by Thread.sleep(1000);to avoid misunderstanding.
In some textbooks, they write statement like this: Thread.currentThread().sleep(1000);which is again not necessary.
25
sleepthe definition of the sleep method is:
public static void sleep(long millis) throws InterruptedException
The method would throw InterruptedException when some other threads interrupt this sleeping thread.
26
interruptUnlike sleep which is a static method,
interrupt is a non-static method of Thread. This means that you need to get hold of a thread before you can interrupt it.
27
interruptAssume that thread A is interrupting thread
B.If thread B is sleeping, then, the
InterruptedException would be thrown to thread B. So control of thread B will be passed to the exception handler.
Note that thread A would not receive any exception.
28
Thread A:
.....
threadB.interrupt();
.....
Thread B:
....try { Thread.sleep(10000);}catch (InterruptedException e) { .....
}......
Assume that Thread B is now sleeping at the Thread.sleep(10000) statement and Thread A is now executing the threadB.interrupt()statement. Then, Thread B would then throw an InterruptedExceptionand control of Thread B would go the catch block.
However, Thread A would not throw any exception and control would flow to the statement after threadB.interrupt().
29
Interrupting a threadNote that when thread A interrupts thread
B but thread B is not sleeping or waiting, then thread B will not be affected in any way except that it has an internal flag to record that someone has interrupt it.
There are two ways to check that a thread has been interrupted.
30
interruptedpublic static boolean interrupted(): again
this method is a static method which means that we can only use it to check whether the current thread has been interrupted. After this call, the internal flag would be set to false again so the second call to this method would return false unless the thread is interrupted again.
31
isInterruptedpublic boolean isInterrupted(): note that
this method is not static which means that we can check whether a particular thread has been interrupted or not, not only the current thread.
The internal flag that records whether the thread has been interrupted would not be changed after this call.
32
threadA:.....threadB.interrupt();.....if (threadB.isInterrupted())
{ ...}... if (threadB.isInterrupted())
{ ...}...
threadB:
....
System.out.println("hello");.............
if (Thread.interrupted()) { ........
}
Assume that threadB is executing the print statement when threadAinterrupts it. threadB would not be affected in any way except thatit has an internal flag to record that it has been interrupted.
Then, threadA executes the threadB.isInterrupted() method to check whether threadB has been interrupted. The returned value of the method is true and therefore the statement in the if block would be executed.
33
interrupt and interruptedThen, threadB executes the statement
Thread.interrupted() to check whether itself has been interrupted. Again, the returned value is true and therefore the statements in the if block would be executed. However, the internal flag would be set to false again.
Then, threadA executes the statement threadB.isInterrupted() again. This time, the returned value is false.
34
SynchronizationWhen more than one thread is making
change to an object problems may occur.
35
class TestObject {
public int a=0;
public void addTwo(int id) {
int b=a;
System.out.println("Thread"+id+":the value of b is "+b);
try {Thread.sleep(1000); } catch (Exception e) {}
a=b+2;
System.out.println("Thread"+id+":the value of a is "+a);
}
}
public class TestThread extends Thread {
TestObject object;
int id;
public TestThread(TestObject obj,int id) {36
object=obj;
this.id=id;
}
public void run() {
for (int i=0;i<4;i++) {
object.addTwo(id);
}
}
public static void main(String st[]) {
TestObject obj=new TestObject();
TestThread thread1=new TestThread(obj,1);
TestThread thread2=new TestThread(obj,2);
thread1.start();
thread2.start();
}
}
37
Thread1:the value of b is 0
Thread2:the value of b is 0
Thread1:the value of a is 2
Thread1:the value of b is 2
Thread2:the value of a is 2
Thread2:the value of b is 2
Thread1:the value of a is 4
Thread1:the value of b is 4
Thread2:the value of a is 4
Thread2:the value of b is 4
Thread1:the value of a is 6
Thread1:the value of b is 6
Thread2:the value of a is 6
Thread2:the value of b is 6
Thread1:the value of a is 8
Thread2:the value of a is 8
38
synchronizedThe problem of last program is that two
threads are trying to change the state of an object at the same time and they interfere with each other.
39
SynchronizedThe synchronized keyword is used to make
sure that a resource can only be accessed by one thread.
When a method of an object is declared as synchronized, then, when a thread wants to invoke the method, it must secure a lock on the object first. Only one thread can secure the lock on the object at anytime.
40
Synchronized methodSo if an object has a number of
synchronized methods and if a thread has secured a lock and is invoking one of the synchronized method, then no other threads can invoke any of the synchronized methods of the object.
When a thread has secured a lock on an object, we say that the thread owns the monitor of the object.
41
Waiting for securing a lock of an objectIf a thread has secured a lock on an object, then all
other threads who also want to secure the lock has to wait. Note that this wait is not the same as the wait state which we will mentioned later.
When the thread that has secured the lock of an object finally releases the lock, then one of the threads that are waiting for the lock can now success in securing the lock and proceed.
However, when a thread has secured a lock on an object, other threads may still involve non-synchronized methods of the object.
When a thread has secured the lock on an object, it is free to involve other synchronized methods of the object.
42
class TestObject {
public int a=0;
synchronized public void addTwo(int id) {
int b=a;
System.out.println("Thread"+id+":the value of b is "+b);
try {Thread.sleep(1000); } catch (Exception e) {}
a=b+2;
System.out.println("Thread"+id+":the value of a is "+a);
}
}
public class TestThread extends Thread {
TestObject object;
int id;
public TestThread(TestObject obj,int id) {43
object=obj;
this.id=id;
}
public void run() {
for (int i=0;i<4;i++) {
object.addTwo(id);
}
}
public static void main(String st[]) {
TestObject obj=new TestObject();
TestThread thread1=new TestThread(obj,1);
TestThread thread2=new TestThread(obj,2);
thread1.start();
thread2.start();
}
}
44
Thread1:the value of b is 0
Thread1:the value of a is 2
Thread2:the value of b is 2
Thread2:the value of a is 4
Thread1:the value of b is 4
Thread1:the value of a is 6
Thread2:the value of b is 6
Thread2:the value of a is 8
Thread1:the value of b is 8
Thread1:the value of a is 10
Thread2:the value of b is 10
Thread2:the value of a is 12
Thread1:the value of b is 12
Thread1:the value of a is 14
Thread2:the value of b is 14
Thread2:the value of a is 16
45
Buffer exampleConsider a fixed size buffer of integers
which allows some producers to put integers to it and allows some consumers to get integers from it.
The integers are removed in the first-in-last-out order. That is, it operates like a stack.
Let's assume that there are two methods called get and put of the buffer which allows consumers and producers to get and put integers respectively.
46
Buffer exampleSince there are many consumers and many
producers, the two methods must be declared as synchronized.
So the two methods should declare like this:synchronized public void put(int i) {...}synchronized public int get() {....}
47
Buffer exampleWe need to solve two problems:
what should we do if we want to get an integer from the buffer but the buffer is empty?
what should we do if we want to put an integer to the buffer but the buffer is full?
One solution is to use exception. That is, the methods will throw an exception whenever the above two situations happen.
48
public class Buffer {
private int elem[]=new int[10];
private int noElems;
/** Creates a new instance of Buffer */
synchronized public void put(int i) throws Exception {
if (noElems==10)
throw new Exception("buffer is full");
elem[noElems++]=i;
}
synchronized public int get() throws Exception {
if (noElems==0)
throw new Exception("buffer is empty");
return elem[--noElems];
}
}49
Buffer exampleThe problem of last example is that if a
consumer really need to put an integer to the buffer, it must do it using a loop because the first attempt may not be successful.
50
Buffer exampleCode for producer:.....
while (true) {
try {
buffer.put(i);
break;
}
catch (Exception e) {
}
}
51
Buffer examplecode for consumer:.....
while (true) {
try {
i=buffer.get();
break;
}
catch (Exception e) {
}
}
52
Buffer exampleSo you can see that the code for using the
buffer is very complicated.We can solve this problem by using the
wait method and notify or notifyAll methods.
53
wait, notify, notifyAllAll of these are methods of Object. Since
all Java classes are subclasses of Object, this means that all classes have these three methods.
Before a thread can invoke one of these three methods of an object, the thread must own the monitor of the object first. Otherwise an exception would be thrown.
54
WaitWhen a thread invokes the wait method of
an object, the thread will go to the wait state and release the monitor of the object.
When a thread is in the wait state and another thread interrupts the former, an InterruptedException would be thrown to the former.
Then if there are threads wanting to acquire the monitor, one of them would successfully do so.
55
notifyAssume that thread A has invoked the wait
method of an object, and another thread B has acquired the monitor of the object. Now, thread B invokes the notify method of the object, then, one of the threads that have invoked the wait method of the object will go back to the ready mode. However, the thread will try to acquire the monitor of the object first before it go to the running states.
56
NotifyAllThis is similar to the notify method except
that all threads which are waiting at the object would be going back to the ready state.
57
notify or notifyAll?So which one should be used?If you wake up a thread and then the
thread cannot go ahead, there is a possibility that the thread would go to wait again. Then we may have all the threads waiting and therefore we end up with a deadlock.
58
notify or notifyAllSo using notifyAll is a safe option.
59
public class Buffer2 {
private int elem[]=new int[10];
private int noElems;
/** Creates a new instance of Buffer */
synchronized public void put(int i) {
while (noElems==10) {
try { wait();} catch (Exception e) {}
}
elem[noElems++]=i;
notifyAll();
}
synchronized public int get() throws Exception {
while (noElems==0) {
try { wait();} catch (Exception e) {}
}
notifyAll();
return elem[--noElems];
}
}
60
wait, notify, notifyAllNote that the code that use this method is
now: buffer.put(3); or int i=buffer.get();
So you can see that the code is much simpler than the one you see when exception method is used.
61
wait, notify, notifyAllNote that when a thread executes the wait
method of an object, it will release the monitor of the object.
62
wait, notify, notifyAllIf the thread owns n monitors and it
execute the wait method of an object, it will still have (n-1) monitors.
When another thread has finished with object and invoke the notify or notifyAll method, then one thread or all threads will go back to the ready mode. But only one can acquire the monitor and proceed.
63
RunnableRunnable is an interface which has only
one method which is:public void run();
Runnable is not a thread but we can use it to create a thread.
There is a constructor of Thread which accepts a Runnable as parameter.
When you start the thread, the run method of the Runnable would be executed.
64
Runnablepublic class MyRunnable implements Runnable {
private String st;
/** Creates a new instance of MyRunnable */
public MyRunnable(String st) {
this.st=st;
}
public void run() {
for (int i=0;i<10;i++) {
try { Thread.sleep(1000); } catch (Exception e) {}
System.out.println(st);
}
65
Runnable }
public static void main(String st[]) {
MyRunnable r1=new MyRunnable("hello");
MyRunnable r2=new MyRunnable("world");
Thread th1=new Thread(r1);
Thread th2=new Thread(r2);
th1.start();
th2.start();
}
}
66
synchronized keywordWe have used the synchronized keyword to
declared a method can only be invoked by one thread at a time.
In fact, when you have successfully acquire the monitor of an object by invoking a synchronized method of the object, no other threads can invoke any synchronized methods of the object.
67
synchronizedThere is another of acquiring the monitor of
an object:
synchronized (object) { .... // the current thread has acquired the // monitor of object.}
68
synchronizedBut this method is not to be advised. It is much better to use synchronized
methods instead of using the synchronized keyword on an object.
69