接《java并发编程(五)任务执行》
前面几章我们一直是创建和开启线程,而有时候我们要结束任务或线程,这并不是很容易的,因为,java 并没有提供任何机制来安全终止线程(在未来的jdk版本中会不会加入呢?)它提供了中断。这是一种机制,能够在一个线程终止另一个线程的工作。
public class PrimeGenerator implements Runnable { private List<BigInteger> primes = new ArrayList<BigInteger>(); private volatile boolean canceled; @Override public void run() { BigInteger bigInteger = BigInteger.ONE; while (!canceled) { bigInteger = bigInteger.nextProbablePrime(); synchronized (this) { primes.add(bigInteger); } } } public void cancel() { this.canceled = true; } public synchronized List<BigInteger> get() { return new ArrayList<BigInteger>(primes); } }现在我们要让一个素数生成器运行1秒后停止,(虽然不是很精确,因为每一条代码是有延时的),我们可以用try finally 来完成,以保证线程会停止,否则线程会一直消耗CPU时钟周期,导致JVM退出。
List<BigInteger> aSecondOfPrimes() throws InterruptedException { PrimeGenerator generator = new PrimeGenerator(); new Thread(generator).start(); try { Thread.sleep(1000); } finally { generator.cancel(); } return generator.get(); }
try { ... } catch (InterruptedException e) { Thread.currentThread().interrupt(); }通常,我们用中断来取消任务比检查标记更好,是最合适的取消任务方式,我们看一个更加健壮的获得素数的类。
public class PrimeProducer extends Thread{ private final BlockingQueue<BigInteger> queue; public PrimeProducer(BlockingQueue<BigInteger> queue) { this.queue = queue; } @Override public void run() { try { BigInteger p = BigInteger.ONE; while(!Thread.currentThread().isInterrupted()) //①用线程的状态来检查 queue.put(p = p.nextProbablePrime()); } catch (InterruptedException e) { //中断将线程退出 } } public void cancel() { interrupt(); } }
public static void timeRun(Runnable r ,long timeout, TimeUnit unit) { Future<?> task = taskExec.submit(r); try { task.get(timeout,unit); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (TimeoutException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { task.cancel(true); } }
public class ReadThread extends Thread { private static final int BUFSZ = 1024; private final Socket socket; private final InputStream in; public ReadThread(Socket socket, InputStream in) { this.socket = socket; this.in = in; } @Override public void interrupt() { try { socket.close(); } catch (IOException e) { } finally { super.interrupt(); } } @Override public void run() { byte[] buf = new byte[BUFSZ]; int count; try { while (true) { count = in.read(buf); if (count < 0) break; else if (count > 0) processBuffer(buf, count); } } catch (Exception e) { } } }我们看到 如果只终止ReadThread线程是没用的,socket是不能关闭的,所以我们要重写interrupt方法 将socket关闭。当然还要调用父类的interrupt
interface CancellableTask<T> extends Callable<T> { void cancel(); RunnableFuture<T> newTask(); }
public abstract class SocketUsingTask<T> implements CancellableTask<T> { private Socket socket; protected synchronized void setSocket(Socket s) { socket = s; } @Override public synchronized void cancel() { try { if (socket != null) socket.close(); } catch (Exception e) { } } @Override public RunnableFuture<T> newTask() { return new FutureTask<T>(this) { @Override public boolean cancel(boolean mayInterruptIfRunning) { try { SocketUsingTask.this.cancel(); } catch (Exception e) { } finally { //不建议将return 写在finally中 } return super.cancel(mayInterruptIfRunning); } }; } }
public class CancellingExecutor extends ThreadPoolExecutor { public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { if (callable instanceof CancellableTask) return ((CancellableTask<T>) callable).newTask(); else return super.newTaskFor(callable); } }
public class TTT { public static void main(String[] args) { CancellingExecutor cancellingExecutor = new CancellingExecutor(10, 20, 200, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); Future<String> future = cancellingExecutor.submit(new SocketUsingTask<String>() { @Override public String call() throws Exception { return "hello"; } }); future.cancel(true); } }
public class LogService { private final BlockingQueue<String> queue; private final LoggerThread loggerThread; private final PrintWriter printWriter; private volatile boolean isShutdown; private int reservation; public LogService(BlockingQueue<String> queue, boolean isShutdown, PrintWriter printWriter) { this.queue = queue; this.loggerThread = new LoggerThread(); this.printWriter = printWriter; } public void start() { loggerThread.start(); } public void stop() { synchronized (this) { isShutdown = true; } loggerThread.interrupt(); } public void put(String msg) throws InterruptedException { synchronized (this) { if (isShutdown) throw new IllegalStateException(); ++reservation; } queue.put(msg); } private class LoggerThread extends Thread { @Override public void run() { try { while (true) { try { synchronized (LogService.this) { if (isShutdown && reservation == 0) break; } String msg = queue.take(); printWriter.write(msg); synchronized (LogService.this) { --reservation; } } catch (InterruptedException e) { e.printStackTrace(); } } } finally { // 接到interrupt会执行 printWriter.close(); } } } }
public class LogService { private static final TimeUnit UNIT = null; private static final long TIMEOUT = 0; private final ExecutorService exec = newSingleThreadExecutor(); public void start() { } public void stop() { try { exec.shutdown(); exec.awaitTermination(TIMEOUT, UNIT); } finally { writer.close(); } } public void log(String msg) { try { exec.submit(new WriteTask(msg)); } catch (Exception e) { } } }
直接看书中的例子,这个不是很常用,粘过来,以备用吧。
public class IndexingService { private static final File POISON = new File(""); private final IndexerThread consumer = new IndexerThread(); private final CrawlerThread producer = new CrawlerThread(); private final BlockingQueue<File> queue; private final FileFilter fileFilter; private final File root; class CrawlerThread extends Thread { class IndexerThread extends Thread { public void start() { producer.start(); consumer.start(); } /* Listing 7.18 */ } /* Listing 7.19 */ } public void stop() { producer.interrupt(); } public void awaitTermination() throws InterruptedException { consumer.join(); } }
public class CrawlerThread extends Thread { public void run() { try { crawl(root); } catch (InterruptedException e) { /* fall through */ } finally { while (true) { try { queue.put(POISON); break; } catch (InterruptedException e1) { /* retry */ } } } } private void crawl(File root) throws InterruptedException { // ... } }
public class IndexerThread extends Thread { public void run() { try { while (true) { File file = queue.take(); if (file == POISON) break; else indexFile(file); } } catch(InterruptedException consumed) { }  } }
boolean checkMail(Set<String> hosts, long timeout, TimeUnit unit) throws InterruptedException { ExecutorService exec = Executors.newCachedThreadPool(); final AtomicBoolean hasNewMail = new AtomicBoolean(false); try { for (final String host : hosts) { exec.execute(new Runnable() { @Override public void run() { if (check(host)) hasNewMail.set(true); } }); } } finally { exec.shutdown(); exec.awaitTermination(timeout, unit); } return hasNewMail.get(); }
设计一个TrackingExecutor类继承AbstractExecutorService 重写execute 当执行时被中断记录在集合里。
public class TrackingExecutor extends AbstractExecutorService { private final ExecutorService exec; private final Set<Runnable> taskCancellAtShutdown = Collections.synchronizedSet(new HashSet<Runnable>()); public TrackingExecutor(ExecutorService exec) { this.exec = exec; } public List<Runnable> getCancelledTask() { if(!exec.isTerminated()) throw new IllegalStateException(); return new ArrayList<Runnable>(taskCancellAtShutdown); } @Override public void execute(Runnable command) { exec.execute(new Runnable() { @Override public void run() { try { command.run(); } finally { if (isShutdown() && Thread.currentThread().isInterrupted()) taskCancellAtShutdown.add(command); } } }); } ... }
public abstract class WebCrawler { private volatile TrackingExecutor exec; private final Set<URL> urlToCrawl = new HashSet<URL>(); public synchronized void start() { exec = new TrackingExecutor(Executors.newCachedThreadPool()); for (URL url : urlToCrawl) submitCrawlTask(url); urlToCrawl.clear(); } public synchronized void stop() { try { saveUncrawled(exec.shutdownNow()); if(exec.awaitTermination(timeout, unit)) saveUncrawled(exec.getCancelledTask()); }finally { exec = null; } } protected abstract List<URL> processPage(URL url); private void saveUncrawled(List<Runnable> uncrawled) { for (Runnable task : uncrawled) { urlToCrawl.add(((CrawTask)task).getUrl()); } } private void submitCrawlTask(URL u) { exec.execute(new CrawTask(u)); } private class CrawTask implements Runnable { private final URL url; public CrawTask(URL url) { this.url = url; } @Override public void run() { for (URL link : processPage(url)) { if(Thread.currentThread().isInterrupted()) return; submitCrawlTask(link); } } public URL getUrl() { return url; } } }
class UELogger implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { //进行错误日志的捕获 } }可以通过Thread. setUncaughtExceptionHandler 设置
public class Hook { public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { System.out.println("!!"); } })); } }
public void start() { Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { //TODO } })); }
版权声明:本文为博主原创文章,未经博主允许不得转载。