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到最后一个的时候,该线程才会退出。