Java7之多线程 线程的取消与关闭

来源:互联网 发布:centos7 网络配置文件 编辑:程序博客网 时间:2024/05/16 15:53

转载自:http://www.it165.net/pro/html/201402/9239.html

Java没有一种安全的抢占式方法来停止线程,只有一些协作式机制。其中一种协作机制能设置某个“已请求取消”标志,而任务将定期查看该标志。如果设置了这个标志,那么任务将提前结束。举例如下:

view sourceprint?
01.publicclass PrimeGenerator implementsRunnable {
02.    privatestatic ExecutorService exec = Executors.newCachedThreadPool();
03. 
04.    privatefinal List<biginteger> primes = new ArrayList<biginteger>();
05.    privatevolatile boolean cancelled; // 为了保证可靠,需要volatile类型
06. 
07.    publicvoid run() {
08.        BigInteger p = BigInteger.ONE;// 创建一个大整数类型,初始值为1
09.        while(!cancelled) {
10.            p = p.nextProbablePrime();
11.            synchronized(this) {// 在添加时要确保同步
12.                primes.add(p);
13.            }
14.        }
15.    }
16.    // 设置取消任务的标识cancelled,以防止搜索素数的线程永远执行下去
17.    publicvoid cancel() {
18.        cancelled =true;
19.    }
20.    // 获取已经计算出来的素数
21.    publicsynchronized List<biginteger> get() {// 对ArrayList进行复制,保证正确的遍历
22.        returnnew ArrayList<biginteger>(primes);
23.    }
24. 
25.    staticList<biginteger> aSecondOfPrimes() throwsInterruptedException {
26.        PrimeGenerator generator =new PrimeGenerator();
27.        exec.execute(generator);// 执行这个任务
28.        try{
29.            SECONDS.sleep(1);
30.        }finally {
31.            generator.cancel();// 确保在调用sleep时被中断也能取消素数生成器的任务
32.        }
33.        returngenerator.get();
34.    }
35.}</biginteger></biginteger></biginteger></biginteger></biginteger>

PrimeGenerator使用了一种简单的取消策略:客户代码通过调用cancel来请求取消,PrimeGenerator在每次搜索素数前首先检查是否存在取消请求,如果存在则退出。

 

如果使用这种策略来请求取消,那么当任务调用了一个阻塞方法的时候,可能任何永远不会检查取消标志,因此永远不会结束。如下举例:

 

view sourceprint?
01.classBrokenPrimeProducer extendsThread {
02.    privatefinal BlockingQueue<biginteger> queue;// 阻塞队列
03.    privatevolatile boolean cancelled = false;
04. 
05.    BrokenPrimeProducer(BlockingQueue<biginteger> queue) {
06.        this.queue = queue;
07.    }
08. 
09.    publicvoid run() {
10.        try{
11.            BigInteger p = BigInteger.ONE;
12.            while(!cancelled)
13.                queue.put(p = p.nextProbablePrime());
14.        }catch (InterruptedException consumed) {
15.        }
16.    }
17. 
18.    publicvoid cancel() {
19.        cancelled =true;
20.    }
21.}
22.</biginteger></biginteger>

当生产者将队列添满时,消费者希望取消这个任务。但是由于生产者此时处于阻塞状态,那么cancelled标志将得不到检查,生产者不能从阻塞的方法中恢复过来。

线程中断是一种协作机制,每个线程都有一个boolean类型的中断状态。在Thread类中提供了3个中断方法,如下:

 

view sourceprint?
1.publicvoid interrupt();            // 中断目标线程
2.publicboolean isInterrupted();     // 返回目标线程的中断状态
3.publicstatic boolean interrupted();// 清除当前线程的中断状态,并返回它之前的值。也是清除中断状态的唯一方法

 

(1)interrupt()方法

对于阻塞库方法,如wait、join、sleep方法,都会检查线程何时中断,并且在发现中断时提前返回。调用这个方法会引起这个线程的interrupt状态被清空(设为false),并且会抛出InterruptedException,表示阻塞操作由于中断而提前结束。

当线程在非阻塞状态下中断时,中断状态将被设置。

(2)isInterrupted()方法

这个方法的源代码如下:

 

view sourceprint?
1.publicboolean isInterrupted() {
2. returnisInterrupted(false);
3.}
4.privatenative boolean isInterrupted(boolean ClearInterrupted);

返回这个线程是否被interrupt了,调用这个方法不会影响这个线程的interrupt状态

 

(3)interrupted()方法

来看这个方法的源代码,如下:

 

view sourceprint?
1.publicstatic boolean interrupted() {
2.  returncurrentThread().isInterrupted(true);
3.}
4.privatenative boolean isInterrupted(boolean ClearInterrupted);

调用这个方法会返回当前线程的interrupt状态(true或false),并把当前线程的interrupt状态清空(设为false)。如果在调用的时候返回true,那么除非你想屏蔽这个中断,否则必须对它进行处理 - 可以抛出InterruptedException,或者通过再次调用interrupt()来恢复中断状态。
注意:这个是个静态方法,并且返回的是当前线程状态,并不一定是调用者的线程状态。

使用这几个方法可以解决如上的自定义取消机制与可阻塞的库函数之间交互的问题,如下:

 

view sourceprint?
01.publicclass PrimeProducer extendsThread {
02.    privatefinal BlockingQueue<biginteger> queue;
03. 
04.    PrimeProducer(BlockingQueue<biginteger> queue) {
05.        this.queue = queue;
06.    }
07. 
08.    publicvoid run() {
09.        try{
10.            BigInteger p = BigInteger.ONE;
11.            while(!Thread.currentThread().isInterrupted())// 在在启动寻找素数前进行检测
12.                queue.put(p = p.nextProbablePrime());
13.        }catch (InterruptedException consumed) {
14.            /* Allow thread to exit */
15.        }
16.    }
17. 
18.    publicvoid cancel() {
19.        interrupt();
20.    }
21.}</biginteger></biginteger>

0 0
原创粉丝点击