`
碧海山城
  • 浏览: 189714 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

关于java线程(3)--中断任务

阅读更多

 

线程的状态四种:

1.新建 new,线程被创建时,会短暂的处于这种状态,他已经分配了必需的资源,并执行了初始化,

2.就绪Runnable,这种状态下,只要调度器把时间片分配给线程,线程就可以运行。

3.阻塞Blocked线程能够运行,但是某个条件阻塞了,调度器将忽略线程,不会分配线程任何CPU时间,直到线程重新进入就绪状态

4.死亡Dead,处于死亡或终止状态的线程将不再是可调度的,并且再也不会得到CPU时间

 

A进入阻塞的条件

1.调用sleep使任务进入休眠状态,

2.通过调用wait使线程挂起,直到线程得到了notify/notifyAll消息

3.等待IO操作完成

4.任务试图在某个对象上调用其同步方法,但是对象锁不可用,另一个任务已经获取了这个锁

5.其他一些阻塞操作,比如BlockQueue.put

 

B.简单的中断处理方式

正在处理的任务,让他停止,最简单的方式就是自己维持一个cancel的标志,类似这样:

 

 

 

 

private volatile boolean cancelled;

public void run(){
   while(!cancelled){
           //do sth
   }
}

 

 

但是这种方式如果有阻塞的话就不行了,因此这时候根本不能走到判断的代码上。

 

一般方法的完成时间可以取决于它要做的事情,以及是否有足够的计算资源,而阻塞的方法还取决于一些外部条件,比如到期时间,I/O,另一个线程的动作(释放一个锁),一般方法在他们的工作做完后即结束,阻塞方法比较难预测,因为他们取决于外部事件。

 

C.响应中断的阻塞

 

sleepwaitBlockingQueue.put等等是会相应中断的,即可中断的Thread类包含interrupt方法,可以终止被阻塞的任务,这个方法设置线程的中断状态;如果这个线程已经阻塞,或者将执行一个阻塞操作,那么将抛出InterruptedException异常;基本上,针对异常,最好做一些和业务相关的处理,最好不要直接抛出,也不要直接吃掉异常

 

新版的API可以在Executor上调用shutdownNow,他将发送一个interrupt调用给他启动的所有线程。如果中断单一的任务,可以使用Executorsubmit方法来启动任务,就可以持有Future对象,调用它的cancel方法。Cancel方法有一个参数,mayInterruptIfRunning,对于响应中断的任务,它表示发送中断信息,请求中断当前正在运行的线程;如果是false,则表示“如果还没有启动,不要运行这个任务”,这可能对那些不能中断的任务是有效地。

 

 

D.检查中断

另外调用中断方法时,如果有可相应中断的方法,那么就会抛出异常发生中断,不然什么也不会发生。因此,如果是这种情况,需要用下面的方式来退出

 

interrupt只是设置线程的中断状态,被中断的线程,可以通过调用interrupted来轮询中断状态(这类似于前面最简单的中断处理方式),该方法还会同时清除中断状态。这不仅仅告诉你interrupt是否被调用。而且还可以清除中断状态,确保不会通知你两次。如果只是单独的查询,可以使用Threaad.isInterrupted方法


 

void run(){
		try{
			//判断是否中断,并且清除中断状态
			while(!Thread.interrupted()){
				
		}catch(InterruptedException e){
			println "exception "+e
		}
} 

 

D.不响应中断阻塞

IOSyn是不可中断的阻塞

1.针对I/O,有一个麻烦,但是有效地方案,即阻塞的时候直接关闭I/O.而不是靠阻断去关闭。

2.另外,nio类提供了可相应中断的类,被阻塞的通道会自动地响应中断。Nio的非阻塞I/O也不支持可中断i/o,但是可以通过关闭通道或者请求Selector上的唤醒来取消阻塞操作

 

<!--[if !supportLists]-->3.<!--[endif]-->对于锁的阻塞,不同线程去获取锁的时候会阻塞,一个线程内,调用两个syn的方法是不会阻塞的,因为锁是可重入的,当前线程已经获得了锁。另外,如果是用Lock去获取锁的话,那么它会可以响应中断

 

 

不可响应中断的阻塞可能需要用一些猥琐的办法处理,比如io,需要将io资源在操作线程之外控制,并且在中断的时候显示的调用它的close方法。如果是显示的操作Thread,那么可以重写interrupt方法:

 

 

class IOBlocked2 extends Thread{
	InputStream inj;
	Socket socket;
	IOBlocked2(){
		socket=new Socket("localhost",8080)
		this.inj=socket.getInputStream()
	}
	
	public void interrupt(){
		try{
			println "interruptSelf"
			socket.close();
		}catch(IOException e){
		
		}finally{
			super.interrupt()
		}
	}
	
	public void run(){
		try{
			println "waiting for read"
			inj.read();
		}catch(IOException e){
			if(Thread.currentThread().isInterrupted()){
				println "interrpted"
			}else{
				println "ioException"
			}
		}
		println "io over"
	}
}
 

如果是使用ExecuterService,那么可以通过Futurecancel方法取消,Future对象是在提交给ExecuterService的使用由newTaskFor方法创建的,因此可以重写该方法:

 

 

interface CancellableTask<T> extends Callable<T>{
	void cancel();
	RunnableFuture<T> newTaskFor();
}

class CancellableExecutor extends ThreadPoolExecutor{
	
	public CancellableExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	protected<T> RunnableFuture<T> newTaskFor(Callable<T> callabled){
		if(callabled instanceof CancellableTask)
			return ((CancellableTask)callabled).newTaskFor();
		else
			return super.newTaskFor(callabled);
	}
}


abstract class SocketUsingTask<T> implements CancellableTask<T>{
	InputStream inj;
	Socket socket;
	 
	public SocketUsingTask() throws Exception{
		socket=new Socket("localhost",8080);
		this.inj=socket.getInputStream();
	}
	
	public void cancel(){
		try{
			System.out.println( "cancelSelf");
			socket.close();
		}catch(IOException e){
			System.out.println(e);
		}
	}
	
	public RunnableFuture<T> newTaskFor(){
		return new FutureTask<T>(this){
			public boolean cancel(boolean mayInterruptIfRunning){
				try{
					SocketUsingTask.this.cancel();
				}finally{
					return super.cancel(mayInterruptIfRunning);
				}
			}
		};
	}
	
}

 

F.不响应中断----不可取消的任务

 

Thread.sleepBlockingQueue.put等操作,是响应中断的,但是也可以用另外一种处理策略:保存中断状态

 

有些任务拒绝被中断,这使得它们是不可取消的。但是,不可取消的任务也应该尝试保留中断状态,以防在不可取消的任务结束之后,调用栈上更高层的代码需要对中断进行处理。下面的代码,方法等待一个阻塞队列,直到队列中出现一个可用项目,而不管它是否被中断。为了方便他人,它在结束后在一个 finally 块中恢复中断状态,以免剥夺中断请求的调用者的权利。(它不能在更早的时候恢复中断状态,因为那将导致无限循环 —— BlockingQueue.take() 将在入口处立即轮询中断状态,并且,

如果发现中断状态集,就会抛出 InterruptedException。)

 

 

public Task getNextTask(BlockingQueue<Task> queue) {
    boolean interrupted = false;
    try {
        while (true) {
            try {
                return queue.take();
            } catch (InterruptedException e) {
                interrupted = true;
                // fall through and retry
            }
        }
} finally {
	//在返回前恢复中断状态,不要掩盖中断状态
        if (interrupted)
            Thread.currentThread().interrupt();
    }
}
 

F.Thread.stopThread.suspend被废除了

线程的Resumesuspendstop方法都已经被废弃,因为他们是极度不安全的,参考:

为什么 Thread.stop和Thread.suspend等被废弃了?

Why Are Thread.stop, Thread.suspend,

Thread.resume and Runtime.runFinalizersOnExit Deprecated?

分享到:
评论

相关推荐

    Java-并发-Java线程中断与停止线程详解

      Java 中的线程中断是一种线程间的协作模式,通过设置线程的中断标志并不能直接终止该线程的执行,而是被中断的线程根据中断状态自行处理。即“线程中断”并不是字面意思——线程真的中断了,而是设置了中断标志...

    java线程和容器专题课程第一部分

    java线程和容器专题课程第一部分,共两部分。详细讲解java线程的一些知识和技术原理。从性能的⻆度看,如果没有任务会阻塞,那么在单处理器机器上就没有意义使用多线程。java的线程机制是抢占式的,这表示调试 机制...

    java通过Python命令执行datax任务调度

    1、通过java调用Python命令执行datax任务调度 2、自动开始任务和调度结束关闭任务调度释放内存 3、如果我们在cmd使用命令调度,执行完毕后无法释放内存,会造成内存泄露不足,出现报错“Error occurred during ...

    线程的基本概念、线程类、任务类、线程优先级、sleep()方法、yield()方法、join方法、interrupt()方法

    线程的基本概念、线程类、任务类、线程优先级、sleep()方法(休眠)、yield()方法...线程的中断是指在一个线程中断另一个线程的执行。在Java中,可以使用Thread类的interrupt()方法实现线程的中断。(run方法执行完毕)

    线程超时死掉

    Future接口是Java线程Future模式的实 现,可以来进行异步计算。 Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时 间之后,我就便...

    92道Java多线程与并发面试题含答案(很全)

    Java并发编程的核心概念包括: 线程(Thread):线程是程序执行流的最小单元。...原子操作(Atomic Operations):原子操作是不可中断的操作,即在多线程环境中,这些操作要么完全执行,要么完全不执行。

    Android-Android可以任意切换线程的任务队列TQueue

    一个 Android 开发库, 可以任意切换线程的链式调用任务队列, 可添加定时, 延时任务, 统一异常处理(Ceased 中断),但不影响整个任务链的运行.

    针对于Executor框架,Java API,线程共享数据

    Executor框架是Java并发编程中的一个重要工具,它提供了一种管理线程池的方式,使得我们可以更方便地管理线程的生命周期和执行线程任务。 原子操作是指不可被中断的操作,要么全部执行成功,要么全部不执行。原子...

    并发编程实践,全面介绍基础知识、JVM同步原语、线程安全、低级并发工具、线程安全容器、高级线程协作工具、Executor部分等

    详细介绍java并发编程相关知识: 基础知识   并发与并行   Java并发演进历史   Java并发模型   线程模型   存储模型 JVM同步原语 volatile CAS 线程安全 ...  线程的中断与任务的取消   其他

    Quartz调度、终止执行的任务

    使用Quartz调度任务,根据需要人为的终止某个任务,适用于很多常见的场景

    java7源码-Concurryency-Learning:并发编程学习笔记

    线程中断的控制 线程的Hibernate和恢复 等待线程的终止 守护线程的创建和运行 线程中不可控异常的处理 线程局部变量的使用 线程的分组 线程组中不可控异常的处理 使用工程类创建线程 本章内容包括: 使用...

    JAVA并发编程实践_中文版(1-16章全)_1/4

    6.1 在线程中执行任务 6.2 executor 框架 6.3 寻找可强化的并行性 第7章 取消和关闭 7.1 任务取消 7.2 停止基于线程的服务 7.3 处理反常的线程终止 7.4 jvm关闭 第8章 应用线程池 8.1 任务与执行策略问的隐性耦合 ...

    java8源码-JavaSE-Code:JavaSE的代码练习与学习笔记总结

    线程是进程中的子任务 interrupted与isInterrupted的区别: interrupted是Thread类的静态方法,里面调用了isTnterrupted方法[currentThread().isInterrupted()],测试当前线程是否已经中断,线程的中断状态由该方法清除 ...

    Java并发编程实战

    6.1.2 显式地为任务创建线程 6.1.3 无限制创建线程的不足 6.2 Executor框架 6.2.1 示例:基于Executor的Web服务器 6.2.2 执行策略 6.2.3 线程池 6.2.4 Executor的生命周期 6.2.5 延迟任务与周期任务 6.3 找...

    Java 7并发编程实战手册

    1.5 线程中断的控制 11 1.6 线程的休眠和恢复 15 1.7 等待线程的终止 17 1.8 守护线程的创建和运行 20 1.9 线程中不可控异常的处理 24 1.10 线程局部变量的使用 26 1.11 线程的分组 30 1.12 ...

    interrupt()和线程终止方式_动力节点Java学院整理

    线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示位,以...

    java乐器源码-concurrency:Java并发编程知识梳理以及常见处理模式featuresandpatterns

    分工(如何高效地拆解任务并分配给线程)Fork/Join 框架 同步(指的是线程之间如何协作)CountDownLatch 互斥(保证同一时刻只允许一个线程访问共享资源)可重入锁 如何学习 跳出来,看全景,站在模型角度看问题...

    Java并发编程(学习笔记).xmind

    (4)用户界面具备更短的响应时间:现代GUI框架中大都使用一个事件分发线程(类似于中断响应函数)来替代主事件循环,当用户界面用有事件发生时,在事件线程中将调用对应的事件处理函数(类似于中断处理函数) ...

    Java并发编程实践 PDF 高清版

    本书的读者是那些具有一定Java编程经验的程序员、希望了解Java SE 5,6在线程技术上的改进和新特性的程序员,以及Java和并发编程的爱好者。 目录 代码清单 序 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的...

    Java并发编程part2

    6.1 在线程中执行任务 6.2 executor 框架 6.3 寻找可强化的并行性 第7章 取消和关闭 7.1 任务取消 7.2 停止基于线程的服务 7.3 处理反常的线程终止 7.4 jvm关闭 第8章 应用线程池 8.1 任务与执行策略问的隐性耦合 ...

Global site tag (gtag.js) - Google Analytics