public class PrimeGenerator implements Runnable { private final List<BigInteger> list = new ArrayList<BigInteger>(); private volatile boolean cancell; @Override public void run() { BigInteger big = BigInteger.ONE; while (!cancell) { big = big.nextProbablePrime(); synchronized (list) { list.add(big); } } } public List<BigInteger> get() { synchronized (list) { return new ArrayList<BigInteger>(list); } } public void setCancell(boolean cancell) { this.cancell = cancell; } public List<BigInteger> aSecondOfPrimer(PrimeGenerator p) throws Exception { new Thread(p).start(); try { Thread.sleep(10); } finally { this.setCancell(true); } return p.get(); } public static void main(String[] args) throws Exception { PrimeGenerator p = new PrimeGenerator(); System.out.println(p.aSecondOfPrimer(p)); } }
最简单的中断方式,使用一个volatile的boolean变量,控制终止。但是不一定signal后就会马上终止,可能在在执行run的一些代码的时候,会出现延迟,甚至会出错。
不过我们把signal放在finally块中,保证一定会执行。
有的时候,这种方式不一定就是安全的,例如有一些类自身就有阻塞的行为,例如BlockingQueue类型,从以下代码可以看出:
package com.test.db; import java.math.BigInteger; import java.util.concurrent.BlockingQueue; public class BlockTest implements Runnable { private final BlockingQueue<BigInteger> queue = new ArrayBlockingQueue<BigInteger>( 1); private volatile boolean cancell; // 生产者线程 @Override public void run() { BigInteger big = BigInteger.ONE; while (!cancell) { try { queue.put(big=big.nextProbablePrime()); } catch (InterruptedException e) { e.printStackTrace(); } } } public void setInterrupted() { cancell = true; } public void consumer(BlockTest b) { new Thread(b).start(); try { while (true) try { System.out.println(queue.take()); //System.out.println("size :"+queue.size()); } catch (InterruptedException e) { e.printStackTrace(); } } finally { b.setInterrupted(); } } public static void main(String[] args) { BlockTest b = new BlockTest(); b.consumer(b); } }
为什么说这是unreliable,我们可以看一下ArrayBlockingQueue的源代码,先看一下put
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); final E[] items = this.items; final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { try { while (count == items.length) notFull.await(); } catch (InterruptedException ie) { notFull.signal(); // propagate to non-interrupted thread throw ie; } insert(e); } finally { lock.unlock(); } }
我们指定的capacity的是1,也就是当count和items.length相等的时候,这个queue会被阻塞。
问题就在于:当生产者线程的put>take,这个时候queue会被很快填满.此时如果take速度比较慢,并且signal中断,这个时候是没有办法停止的,除非当take到最后一个的时候,该线程才会退出。