欢迎使用CSDN-markdown编辑器

《Java 线程编程》 学习笔记5

第5章 完美终止线程

5.1 中断线程:interrupt()

  1. 当一个线程运行时,另一个线程可以调用对应的 Thread 对象的 interrupt() 方法来中断它:public void interrupt()
  2. 这个方法只是在目标线程中设置一个标志位,表示它已经被中断,并立即返回。该方法可能抛出 SecurityException,表示发出中断请求的线程没有权限中断其他线程
    • 在 Thread 上调用 checkAccess() 方法可以进行安全性检查,这个方法又会调用 SecurityManager 的 checkAccess(Thread) 方法。

警告:
SecurityException 属于 RuntimeException 的一个子类,因此,对于可能抛出此异常的 Thread 或 ThreadGroup 的任何方法,并不需要 try/catch 块。默认时,应用程序没有定义 SecurityManager。所以,在代码中需要进行一般性检查,使用方法 System.getSecurityManager()。如果返回 null,则表示没有安装 SecurityManager。如果没有返回 null,则调用 SecurityManager 时必须小心。常见覆写 SecurityManager 方法:

import java.io.*;  
class PasswordSecurityManager extends SecurityManager {  
    private String password;  
    PasswordSecurityManager(String password) {  
        super();  
        this.password = password;  
    }  
    private boolean accessOK() {  
        int c;  
        //DataInputStream dis = new DataInputStream(System.in);  
        BufferedReader dis = new BufferedReader(new InputStreamReader(System.in));  
        String response;  
        System.out.println("What's the secret password?");  
        try {  
            response = dis.readLine();  
            if (response.equals(password))  
                return true;  
            else  
                return false;  
        } catch (IOException e) {  
            return false;  
        }  
    }  
    public void checkRead(FileDescriptor filedescriptor) {  
        if (!accessOK())  
            throw new SecurityException("Not a Chance!");  
    }  
    public void checkRead(String filename) {  
        if (!accessOK())  
            throw new SecurityException("No Way!");  
    }  
    public void checkRead(String filename, Object executionContext) {  
        if (!accessOK())  
            throw new SecurityException("Forget It!");  
    }  
    public void checkWrite(FileDescriptor filedescriptor) {  
        if (!accessOK())  
            throw new SecurityException("Not!");  
    }  
    public void checkWrite(String filename) {  
        if (!accessOK())  
            throw new SecurityException("Not Even!");  
    }  
}   
5.1.1 中断休眠线程
  1. 代码示例:
public class SleepInterrupt extends Object implements Runnable {
    public void run() {
        try {
            System.out.println("in run - about to sleep for 20 seconds");
            Thread.sleep(20000);
            System.out.println("in run() - woke up");
        } catch(InterruptionException x) {
            System.out.println("in run() - interrupted while sleeping");
            return;
        }
        System.out.println("in run() - doing stuff after nap");
        System.out.println("in run() - leaving normally");
    }

    public static void main(String[] args) {
        SleepInterrupt si = new SleepInterrupt();
        Thread t = new Thread(si);
        t.start();
        // 确保新线程有机会运行一段时间
        try {
            Thread.sleep(2000);
        } 
        catch(InterruptedExcepted x) {
        }
        System.out.println("in main() - interrupting other thread");
        t.interrupt();
        System.out.println("in main() - leaving");
    }
}

/*
运行结果:
    in run()  - about to sleep for 20 seconds
    in main() - interrupting other thread
    in main() - leaving
    in run()  - interrupting while sleeping
*/
5.1.2 待决中断
  1. 上一个示例说明在线程 sleep() 时,会被 interrupt()。另外,如果在调用 sleep() 之前,中断已经被调用,那它会立即抛出 InterruptedException。
public class PendingInterrupt extends Object {
    public static void main(String[] args) {
        if(args.length > 0) {
            Thread.currentThread().interrupt();
        }
    }
    long startTime = System.currentTimeMillis();
    try {
        Thread.sleep(2000);
        System.out.println("was Not interrupted.");
    }
    catch (InterruptedException x) {
        System.out.println("was interrupted");
    }

    System.out.println("elapsedTime = " + (System.currentTimeMillis() - startTime));
}
/*
如果不带参数执行:
    was Not interrupted
    elapsedTime = 2080
带参数执行:
    was interrupted
    elapsedTime = 110
*/
5.1.3 使用 isInterrupted()
  1. 可以在 Thread 对象上调用 isInterrupted() 方法来检查任何线程的中断状态。
  2. public boolean isInterrupted()
5.1.4 使用 Thread.interrupted()
  1. 如果线程被中断,调用该函数,将返回 true,同时清除中断标志位。
  2. public static boolean isInterrupted()
5.1.5 InterruptedException

5.2 挂起和恢复线程运行

  1. 加入某个程序使用一个线程按顺序翻转图片达到动画显示的目的,当动画不可见时,就没有必要继续动画显示,直到窗口可见后,再次恢复动画。
5.2.1 使用淘汰的方法 suspend() 和 resume()

技巧:
这些方法和类已经被 Sun 公司淘汰,说明开发人员应该尽量避免使用它们。淘汰的方法仍然可以使用,但是编译代码时,就会发出警告。淘汰这些方法或类,表示他们过时了,或者使用时比较危险,有可能在将来的 JDK 版本中删除。

  1. suspend() 方法是在 JDK 1.2 中淘汰的方法,因为如果在不合适的时候挂起线程(如锁定共享资源时),此时可能会发生死锁条件(deadlock condition)。
5.2.2 在不恰当的时候挂起
  1. 下面的代码示例通过休眠来减缓运行,使线程更可能在不适当的时候被挂起。
5.2.3 不使用淘汰方法实现挂起和恢复
  1. 示例代码:
public class AlternateSuspendResume extends Object implements Runnable {

    private volatile int firstVal;
    private volatile int secondVal;
    private volatile boolean suspended; // 等待状态变量,用于跟踪让内部线程临时终止运行的请求

    public boolean areValesEqual() {
        return (firstVal == secondVal);
    }
    public void run() {
        try {
            suspend = false;
            firstVal = 0;
            secondVal = 0;
            workMethod();
        } catch(InterruptedException x) {
            System.out.println("interrupted while in workMethod()");
        }
    }
    private void workMethod() throws InterruptedException {
        int val = 1;
        while(true) {
            // 仅当挂起时才运行的代码
            waitWhileSuspended();

            stepOne(Val);
            stepTwo(Val);
            val++;

            // 仅当挂起时才运行的代码
            waitWhileSuspended();

            Thread.sleep(200);
        }
    }
    public void suspendRequest() {
        suspended = true;
    }
    public void resumeRequest() {
        suspended = false;
    }
    private void waitWhileSuspended() throws InterruptedException {
        // 这是一个『繁忙等待』技术的示例
        // 它是非等待条件改变的最佳途径
        // 因为它会不断请求处理器周期来检查执行
        // 更佳的技术是:使用 Java 内置的『等待-通知』机制
        while(suspended) {
            Thread.sleep(200);
        }
    }
}

技巧:
如果在代码中有多个安全的地方可以挂起线程,对所有这些安全地方,应该添加更多的 waitWhileSuspended() 方法调用。只要确保没有在持有锁时允许挂起就行了!应该频繁使用 waitWhileSuspended(),有助于线程对挂起请求的快速反应。同时,要记住,调用 waitWhileSuspended() 会耗费一些处理器资源,因此,也不要用得太频繁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值