- 1.1 Overview
- 2.1 What is an interrupt
- 2.2 Interrupt Mechanism
- 2.3 The two interrupt methods
- 2.4 Check the interrupt flag
- ??? Reminder: Throw exits directly
- 2.5 InterruptedException
- 3.Terminating threads
- 3.1 isAlive()
- 3.2 Terminate a thread (3 ways Overview)
- 3.3 Finish the thread naturally
- 3.4 Daemon Threads
- 3.5 Interrupt the thread
- 4.1 Volatile
- 4.2 Common traps with volatile
- 4.3 Usage: Stop Caching
- 4.4 When not to use volatile
- 4.5 On another point: Thread.yield() may be better than Thread.sleep()
- Homework
1.1 Overview
- Understand how Java interrupts are implemented
- Understand what exceptions are and how to use them with
interrupts - Understand how to terminate threads
- Understand some of the risks of threads and how to mitigate them
1.2 Get a reference to yourself as a thread
Thread.currentThread().interrupt();
1.3 Summary of methods
Thread.sleep(1000)
- Pauses thread from executing for 1000 milliseconds
myThread.join()
join函数解读
- Pauses current thread until myThread has finished executing
- In other words myThread’s run() method has finished
线程A的run方法中调用了线程B的join,此时线程A处于阻塞状态,直到线程B执行完毕或者死亡的时候,线程A才会继续执行。
myThread.interrupt()
- send an interrupt signal to myThread
- This will set myThread’s interrupt flag to true
2.1 What is an interrupt
- An interrupt is an indication to a thread that it should stop what it is doing and do sth else.
- The programmer decides how a thread responds to an interrupt
- A thread sends an interrupt ny invoking interrupt() on the Thread obect to be interrupted.
- For the interrupt mechanism to work correctly, the interrupted thread must support it. (check the interrupt flag)
2.2 Interrupt Mechanism
- The interrupt mechanism is implemented using an internal flag known as the interrupt status.
- Invoking interrupt on a target threads sets this flag
- A thread may check for an interrupt by invoking the static method Thread.interrupted()
- one thread can query the interrupt status of another by using the non-static isInterrupted().
2.3 The two interrupt methods
Thread.interrupted()
is static and checks if the current thread has its interrupted flag set to true.- only works for the thread that it is called from
- The interrupt status is then automatically cleared
mythread.isInterrupted()
is an instance method which checks the Thread object that it is called on.- Can be used to check if a different thread is interrupted
- E.g. if(thread2.isInterrupted() == true)…
- A common error is to mix these two up
2.4 Check the interrupt flag
MyThread myThread = new MyThread()
if (myThread.isInterrupted())
{
} //Correct syntax
//Example 1
//Doesn’t check the interrupt flag! Just ignores it!
class MyThread extends Thread
{
public void run(){
for(int i =1;i <=5;i++){
System.out.println(i);
}
}
public static void main(String args[]){
MyThread t1 = new MyThread();
t1.start();
t1.interrupt();
}
}
??? Reminder: Throw exits directly
try{
...}
catch (FileNotFoundException e){
System.err.println("FileNotFoundException:" + e.getMessage());
throw new SampleException(e);
}
catch (IOException e){
System.err.println("Caught IOException:" + e.getMessage());
}
2.5 InterruptedException
//Example2 Interrupting a thread that stops working
class MyThread extends Thread{
public void run(){
try{
Thread.sleep(1000);
System.out.println("Finished!"); //Not printed
}
catch(InterruptedException e ){
//This doesn't really do anything
System.out.println("I'm interrupted"); //Printed
System.exit(-1);
//This should be used to deal with the exception
}
}
public static void main (String args[]){
MyThread t1 = new MyThread();
t1.start();
try{
t1.interrupt();//Wrong Syntax
}
catch(Exception e)
{
System.out.println("Exception handled" +e);
}
}
}
-
if the thread is sleeping or joining or waiting on another Thread:
-
- InterruptedException is thrown
-
- Interrupted status will be cleared
Do things to tidy up and finish the thread
- Interrupted status will be cleared
-
-
Restoring the interrupted status
public void run(){
while(!Thread.currentThread().isInterrupted())
{
// Doing some heavy operations
try {
Thread.sleep(5000);
}
catch(InterruptedException e)
{
Thread.currentThread().interrupt();
//interrupt again as may need to do something rather than just exit
}
}
}
3.Terminating threads
3.1 isAlive()
- A thread is said to be alive (where isAlive()returns true )when is has been started and still not died.
- isAlive() method returns true if the thread(upon which it is called) is still running and not finished.
- The Thread class comes with an instance method isAlive() to determine whether the thread is in born state or dead state where calling isAlive() returns false.
if(myThread.isAlive())
{
//check something
//myThread.interrupt();
}
The method that you will more commonly use to wait for a thread to finish is called join()
3.2 Terminate a thread (3 ways Overview)
You have no command to force a Thread to stop(in java)
- The thread has finished and exits naturally.
- The thread has been marked as daemon(后台程序) thread. When the parent thread who created this thread terminates, this hread will be forcefully(有力地) terminated.
- The thread has received an interrupt signal, while doing its work.
- It decides to not continue with work and exits the run() method.
- It may also decide to ignore the signal and continue to work.
3.3 Finish the thread naturally
- Or could use a shared Boolean(e.g. pleaseFinish)
- Periodically check to see if pleaseFinish is set to true
- If true, finish thread
挥发性 — volatile
class MyThread extends Thread{
private volatile boolean pleaseFinish = false;
public void run(){
//Periodically check for pleaseFinish to be
//set to true
//Do something
//Finish nturally
}
public void finishThreadPlease(){
pleaseFinish = true;
/*Be careful when using pleaseFinish
If thread is in a non-runnable state, setting a stpo flag variable will have no effect
A thread is in a non-runnale state if
+ Its sleep method is invoked.
+ The thread calls the wait method to wait for a specific condition to be satisfied.
+ The thread is blocking on I/O
*/
}
}
3.4 Daemon Threads
- Cannot start it and then daemon it.
-
myThread.setDaemon(false)
The Worker thread continues to run after parent thread has finished. -
myThread.setDaemon(true)
Worker thread terminates when the parent thread terminates.
public void run(){
WorkerThread t1 = new WorkerThread();
t1.setDaemon(true);
t1.start();
//do sth
//this thread completes
//When this thread completes:
//t1 will also be terminated(automatically)
}
3.5 Interrupt the thread
You should catch an InterruptedException and then stop the thread
public void run()
{
for (int i = 0; i < importantInfo.length; i++)
{
try {
Thread.sleep(4000); }
catch (InterruptedException e)
{
return; }
System.out.println(importantInfo[i]);
}
}
Routinely check for interrupts at strategic points where you can safely stop and cleanup
if (Thread.currentThread.isInterrupted())
{
// cleanup and stop execution
return;
}
public class InterruptThread {
public static void main(String[] args) {
Thread thread1 = new Thread(new WaitRunnable());
thread1.start();
try {
Thread.sleep(1000); } // wait a second to make sure thread1 started
catch (InterruptedException e) {
e.printStackTrace(); }
thread1.interrupt(); } // now interrupt thread1
Example that the interrupted status has been set to false.
private static class WaitRunnable implements Runnable {
@Override
public void run() {
System.out.println("Current time millis : " + System.currentTimeMillis());
try {
Thread.sleep(5000); } // will be asleep when interrupt comes
catch (InterruptedException e) {
System.out.println("The thread has been interrupted");
System.out.println("The thread is interrupted : " + Thread.interrupted(); // the interrupted status has been set to false}
System.out.println("Current time millis : “ + System.currentTimeMillis()); } } }
4.1 Volatile
- Volatile is used to indicate that a variable’s value will
be modified by different threads - Access to the variable is only given to one thread at a
time
public volatile int counter = 0;
4.2 Common traps with volatile
Array
If you declare arr[] as volatile, that means that
- the reference to the array is volatile;
- individual field accesses (e.g. arr[5]) are not thread‐safe
Unary operations
(++, ‐‐) aren’t atomic
volatile int i;
...
i += 5; //NOT SAFE
4.3 Usage: Stop Caching
If a variable is modified, another thread’s cache may go out‐of‐date
If you set a variable to volatile:
- The value of this variable will never be cached thread‐locally
- All reads and writes will go straight to “main memory”;
public class StoppableTask extends Thread {
private boolean pleaseStop;
// private volatile boolean pleaseStop
//Because of volatile while loop cannot cache
// Re-checks pleaseStop every iteration
public void run() {
// While loop caches pleaseStop variable
//This loop will never end
while (!pleaseStop) {
// do some stuff... } }
public void tellMeToStop()
{
pleaseStop = true; } }
4.4 When not to use volatile
- Fields that declared final (never change)
- Variables that are accessed by only one thread
- Complex operations (Even things like x=x+5)
4.5 On another point: Thread.yield() may be better than Thread.sleep()
- yield stops the thread running continuously and gives some time back to the Operating System.
- yield just gives up the thread’s turn, and regains it in
the next round. - sleep() has a slightly larger overhead because it creates a system that includes some kind of timer that will wake the process. (Depends on implementation basically)
Hence yield sometimes better
Homework
- Create several different threads
- One that constantly loops printing out hello
- One that loops printing out hello with a 1 second sleep in between
- Interrupt the threads and see what happens!
- Add interrupt support into them so that you can stop them looping
with an interrupt - Create a shared variable pleaseFinish to terminate the thread
- Try both with and without volatile…