当前位置: 首页 > news >正文

(三)终结任务

花园入口计数

花园有多个入口,希望统计花园每天的总人数。

public class OrnamentalGarden {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0;i<5;i++){
            exec.execute(new Entrance(i));
        }
        TimeUnit.MILLISECONDS.sleep(3000);
        Entrance.cancel();
        exec.shutdown();
        if(!exec.awaitTermination(250, TimeUnit.MILLISECONDS)){
            System.out.println("some tasks were no terminated!");
        }
        System.out.println("Total:"+Entrance.sumEntrance());
    }
}
//
//创建计数器
class Count{
    //记录总的数目
    private int count=0;
    private Random rand = new Random(47);
    public synchronized int increment(){
        int tmp = count;
        //使用随机数,即有一半的时间当前线程会让步,以此增加出错的可能性。
        if(rand.nextBoolean())
            Thread.yield();
        return (count = ++tmp);
    }
    public synchronized int value(){
        return count;
    }
}
/
//定义一个入口类 class Entrance implements Runnable{ //使用一个静态计数器,为每个入口计数 private static Count count = new Count(); private static List<Entrance> entrances = new ArrayList<Entrance>(); //某一个入口的通过人数 private int number =0; //某一个入口的id private final int id; //入口是否关闭 private static volatile boolean canceled=false; public static void cancel(){ canceled = true; } public Entrance(int id){ this.id = id; entrances.add(this); } @Override public void run() { while(!canceled){ synchronized(this){ ++number; } System.out.println("Entrance "+id+": "+getValue()+": Total:"+count.increment()); try{ TimeUnit.MILLISECONDS.sleep(100); }catch(InterruptedException e){ System.out.println("sleep is interrupted!"); } } System.out.println("stopping Entrance "+id+": "+getValue()); } //获得当前入口的人数 public synchronized int getValue(){ return number; } //获得所有入口的总人数,由count计数器给出 public static int getTotal(){ return count.value(); } //统计每个入口的总人数 public static int sumEntrance(){ int sum=0; for(Entrance e:entrances){ sum +=e.getValue(); } return sum; } }

在阻塞时终结

上面的例子中,Entrance.run()循环中包含sleep()的调用。sleep()终将被唤醒,任务又返回循环开始的地方判断canceled标志,从而决定是否跳出循环。但是,sleep()下,它使任务变为阻塞,而我们有时候需要终止被阻塞的任务。上面的代码明显无法满足我们的需求。下面的中断可以才能解决。

中断

在Runnable.run()方法的中间打断它,与等待run()方法对canceled标志进行检查相比,要棘手的多。

在任务的run()方法中间打断它,很像是抛出一个异常,因此java线程中这种类型的异常中断用到了异常。为了在以这种方式终止任务时,返回良好状态,需要仔细编写catch语句以正确清除所有事物。

为了调用interrupt(),必须持有Thread对象。而新的concurrent类库为了避免直接对Thread对象操作,转而使用Executor来执行。

Executor调用shutdownNow(),那么它将发送一个interrupt()给它启动的所有线程。

然而,有时候会想中断某个单一任务,此时应该使用submit()启动任务,该方法可以返回一个Funture<?>对象,使用该对象的cancel()方法可以中断特定的任务。它也是在指定线程上调用interrupt()方法。

当在线程上调用interrupt()时,中断发生的唯一时刻是在任务要进入到阻塞操作或者已经在阻塞操作内部时。

public void interrupt()

Interrupts this thread.
Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
Interrupting a thread that is not alive need not have any effect.

检查中断

当run()方法不处在阻塞时,interrupt()方法便无法停止任务。以下为第二种方法。

当调用interrupt()方法时会产生中断状态,对中断状态进行检查即可。在run方法中,我们应该同时处理阻塞和非阻塞的两种情况。

public class CheckInterrupt {

    public static void main(String[] args) throws InterruptedException {
        Task ts = new Task();
        Thread t = new Thread(ts);
        t.start();
        Thread.sleep(1000);
        t.interrupt();
    }
}
class Task implements Runnable{

    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            try{
                System.out.println("当前线程:"+Thread.currentThread().getId()+" 正在运行!");
                Thread.sleep(100);
            }catch(InterruptedException e){
                System.out.println("当前线程:"+Thread.currentThread().getId()+" 接收到中断请求!");
                Thread.currentThread().interrupt();
            }
        }
    }
}

上面的例子中对阻塞和非阻塞都进行了处理,因此调用interrupt()都可以停止任务的运行。当接收到InterruptedException异常时,会清除Thread.currentThread().isInterrupted()标志,因此若要跳出while循环,必须再次标志上Thread.currentThread().isInterrupted()的中断状态,使用Thread.currentThread().interrupt()即可。

转载于:https://www.cnblogs.com/wuchaodzxx/p/5986047.html

相关文章:

  • Nagios学习笔记四:基于NRPE监控远程Linux主机
  • 红外摄像头与白光摄像头的区别
  • 双击事件
  • 单机运行环境搭建之 --CentOS-6.5安装配置Tengine
  • 【windows】跑大型程序时不要休眠和睡眠
  • JAVA-反射学习
  • js中(与)、|(或)以及^(异或)的二进制使用
  • symfony框架学习
  • 趣解curl
  • CentOS更改yum源与更新系统
  • C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)
  • CSS3盒模型-display:box
  • 2016 10 28考试 dp 乱搞 树状数组
  • Mac 下安装运行Rocket.chat
  • 阶段2-新手上路\项目-移动物体监控系统\Sprint1-声音报警子系统开发\第3节-嵌入式播放器移植...
  • [PHP内核探索]PHP中的哈希表
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • 【刷算法】从上往下打印二叉树
  • ➹使用webpack配置多页面应用(MPA)
  • 03Go 类型总结
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • nfs客户端进程变D,延伸linux的lock
  • nodejs:开发并发布一个nodejs包
  • Protobuf3语言指南
  • Python学习之路16-使用API
  • Sass Day-01
  • spring-boot List转Page
  • Terraform入门 - 3. 变更基础设施
  • Vue.js源码(2):初探List Rendering
  • 闭包--闭包作用之保存(一)
  • 工作中总结前端开发流程--vue项目
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 如何合理的规划jvm性能调优
  • 入手阿里云新服务器的部署NODE
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • - 转 Ext2.0 form使用实例
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​学习一下,什么是预包装食品?​
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • #Lua:Lua调用C++生成的DLL库
  • (1)Android开发优化---------UI优化
  • (11)MATLAB PCA+SVM 人脸识别
  • (3)选择元素——(17)练习(Exercises)
  • (C语言)共用体union的用法举例
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (五)关系数据库标准语言SQL
  • (转)C#调用WebService 基础
  • (转)ORM
  • ..回顾17,展望18
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .gitignore文件_Git:.gitignore