<<java并发编程>>读书笔记之线程中断

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

猜你喜欢

转载自cyril0513.iteye.com/blog/1697198