Download Thread 2

Document related concepts
no text concepts found
Transcript
COMPS311F
Li Tak Sing
Lecture 2
1
Threads
 A 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
Threads
 When you run a Java program, a thread is used to execute
statements in the main method.
3
Threads
 However, 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
Threads
 In 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
Thread
 Some 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
Threads
 Thread 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
Thread
 When 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
Thread
 When 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
Thread
 When 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
Thread
 When 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 Thread
 public 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 Thread
 public 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
17
thread: 0.6062253369356854
thread: 0.9451801315255973
Thread
 Interesting 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
currentThread
 In 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
currentThread
 Since 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
currentThread
 In 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
sleep
 sleep 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
threadA:
.....
threadB.sleep(1000);
threadB:
.....
System.out.printf("abcd");
.....
......
Now, assume that threadA is executing the statement
threadB.sleep(1000) and threadB is executing the print
statement.
23
sleep
 Which 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
sleep
 So 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
sleep
 the 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
interrupt
 Unlike 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
interrupt
 Assume 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 InterruptedException
and control of Thread B would go the catch block.
29
However, Thread A would not throw any exception and control would
flow to the statement after threadB.interrupt().
Interrupting a thread
 Note 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
interrupted
 public 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
isInterrupted
 public 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 threadA
interrupts it. threadB would not be affected in any way except that
it has an internal flag to record that it has been interrupted.
33
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.
interrupt and interrupted
 Then, 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
Synchronization
 When 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
synchronized
 The 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
Synchronized
 The 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 method
 So 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
object
 If a thread has secured a lock on an object, then all other
42
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.
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 example
 Consider 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 example
 Since 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 example
 We 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 example
 The 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 example
Code for producer:
.....
while (true) {
try {
buffer.put(i);
break;
}
catch (Exception e) {
}
}
51
Buffer example
code for consumer:
.....
while (true) {
try {
i=buffer.get();
break;
}
catch (Exception e) {
}
}
52
Buffer example
 So 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, notifyAll
 All 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
Wait
 When 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
notify
 Assume 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
NotifyAll
 This 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 notifyAll
 So using notifyAll is a safe option.
59
60
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];
}
wait, notify, notifyAll
 Note 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, notifyAll
 Note that when a thread executes the wait method of an
object, it will release the monitor of the object.
62
wait, notify, notifyAll
 If 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
Runnable
 Runnable 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
Runnable
public 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 keyword
 We 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
synchronized
 There is another of acquiring the monitor of an object:
synchronized (object) {
.... // the current thread has acquired the
// monitor of object.
}
68
synchronized
 But 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