Download presentation
Presentation is loading. Please wait.
Published byGyles Lang Modified over 9 years ago
1
Li Tak Sing COMPS311F
2
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.
3
Threads When you run a Java program, a thread is used to execute statements in the main method.
4
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.
5
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.
6
Life cycle of a thread
7
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.
8
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.
9
Thread When the start method of a thread is invoked, it enters the Ready state. When the 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.
10
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.
11
Thread When the thread is executing wait method of an object, it enters the wait state and it will stop exection. When some other thread invoke the notify or notifyAll method of the object, the thread would go back to the ready state.
12
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.
13
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.
14
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.
15
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); }
16
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); } }
17
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
18
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 the main method. It is a proof that there are two flows of control, or two threads.
19
currentThread In last example, you actually encounter 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.
20
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.
21
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.
22
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.
23
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");.....
24
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.
25
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.
26
sleep the definition of the sleep method is: public static void sleep(long millis) throws InterruptedExceptionInterruptedException The method would throw InterruptedException when some other threads interrupt this sleeping thread.
27
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.
28
interrupt Assume that a thread A is interrupting a 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.
29
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. However, Thread A would not throw any exception and control would flow to the statement after threadB.interrupt().
30
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.
31
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.
32
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 record whether the thread has been interrupted would not be changed after this call.
33
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. Then, threadA execute 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.
34
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.
35
Synchronization When more than one threads are making change to an object problems may occur.
36
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) {
37
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(); }
38
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
39
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.
40
MT311 Java Application Development and Programming Languages Li Tak Sing ( 李德成 )
41
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.
42
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.
43
Waiting for securing a lock of an object If 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.
44
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) {
45
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(); }
46
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
47
Buffer example Consider a fixed size buffer of integers example 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.
48
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() {....}
49
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.
50
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]; } }
51
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.
52
Buffer example Code for producer:..... while (true) { try { buffer.put(i); break; } catch (Exception e) { }
53
Buffer example code for consumer:..... while (true) { try { i=buffer.get(); break; } catch (Exception e) { }
54
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.
55
wait, notify, notifyAll All of these three 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.
56
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.
57
notify Assume that a thread A has invoked the wait method of an object, and another thread B has acquired the monitor of the object. Now, thread B invoke 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 can proceed.
58
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.
59
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.
60
notify or notifyAll So using notifyAll is a safe option.
61
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]; }
62
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.
63
wait, notify, notifyAll Note that when a thread executes the wait method of an object, it will release the monitor of the object.
64
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.
65
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.
66
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); }
67
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(); } }
68
synchronized keyword We have used the synchronized 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.
69
synchronized There is another of acquiring the monitor of an object: synchronized (object) {.... // the current thread has acquired the // monitor of object. }
70
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.
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.