java线程之Latch设计模式见解

CountDownLatch :(个人理解)使用阀门值,直到阀门值为0之前,一直阻塞线程。实则使用对象锁,不释放对象锁,一直占用资源,(这里是一个缺点)。阀门值为0时,调用释放对象锁的方法,释放资源。应用的场景,我觉得是需要一些线程先完成的前提下,再使用其他线程。也就是我就是要一些重要的线程(也不是特指重要)完成任务之后,接着再执行其他线程。

Table of Contents

demo1-重写CountDownLatch

demo2-子线程任务完成之后执行主线程

demo3-多个CountDownLatch的应用 


本文引用的demo均为转载,其他内容是自己原创。感谢这些demo的提供者。为了部落....O(∩_∩)O哈哈~


demo1-重写CountDownLatch

这个是我在《java高并发详解》中找到的demo (注:有一些自己的调整): 

(readme: 重写了CountDownLatch类以及一些方法。创建了一个自定义异常TimeoutException。应用了一些锁的知识点。(synchronized会一直等待线程释放对象锁而造成阻塞,wait方法会释放对象锁,本程序如果不加该方法的后果就是会一直被阻塞,造成超时。)

四个程序员约定在某个时间到某地聚会,每人都会采用交通工具,最后对按时到达的程序员,输出按时到达。 

package com.mzs.entity;

import java.util.concurrent.TimeUnit;

public abstract class Latch {
	
	protected int limit;	// 阀门值
	protected boolean isLate;	// 是否迟到
	
	public Latch(int limit, boolean isLate) {
		this.limit = limit;
		this.isLate = isLate;
	}
	
	/**
	 * 模拟等待
	 * @param unit	时间单位
	 * @param time	预定的到达时间
	 * @throws InterruptedException	被打断时抛出该异常
	 * @throws TimeoutException	自定义的时间超时异常,当时间超过预定的到达时间时,抛出该异常
	 */
	public abstract void await(TimeUnit unit, long time) throws InterruptedException, TimeoutException;
	
	/**
	 * 阀门值减一
	 */
	public abstract void countDown();
	
	/**
	 * 统计未到达的人数
	 * @return 未到达的人数
	 */
	public abstract int getUnarrived();
}

package com.mzs.entity;

import java.util.concurrent.TimeUnit;

public class CountDownLatch extends Latch {

	public CountDownLatch(int limit, boolean isLate) {
		super(limit, isLate);
	}

	@Override
	public void await(TimeUnit unit, long time) throws InterruptedException, TimeoutException {
		if (time < 0)
			throw new IllegalArgumentException("argument is invalid");
		// 表示预定的到达时间
		long remainingTime = unit.toNanos(time);
		long endTime = System.nanoTime() + remainingTime;
		synchronized (this) {
			while (limit > 0) {
				// 剩余时间小于0,则未按时到达,标记迟到,并抛出自定义超时异常
				if (TimeUnit.NANOSECONDS.toMillis(remainingTime) < 0) {
					this.isLate = true;
					throw new TimeoutException("time is over");
				}
                // 等待的过程中,被打断时,时间进行新的处理。
                this.wait(TimeUnit.NANOSECONDS.toMillis(remainingTime));
				// 计算剩余的时间
				remainingTime = endTime - System.nanoTime();
			}
		}
	}

	@Override
	public void countDown() {
		synchronized (this) {
			// 对阀门值的检查,如果小于0,抛出该异常
			if (limit < 0)
				throw new IllegalStateException("the number of limit is illegal");
			// 阀门值自减,表示已到达
			limit--;
			// 通知阻塞线程
			this.notifyAll();
		}
	}

	@Override
	public int getUnarrived() {
		return limit;
	}
	

}

package com.mzs.entity;

public class TimeoutException extends Exception {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -6499958945796073069L;
	
	private String message;
	
	public TimeoutException(String message) {
		super(message);
	}

}

package com.mzs.entity;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class ProgrammerTravel extends Thread {

	private final Latch latch;	// 阀门值
	private final String programmer;	// 程序员
	private final String transportation;	// 交通工具

	private Logger logger = Logger.getLogger(getClass().getName());

	public ProgrammerTravel(Latch latch, String programmer, String transportation) {
		this.latch = latch;
		this.programmer = programmer;
		this.transportation = transportation;
	}

	@Override
	public void run() {
		logger.info(programmer + " starts to take the transportation [ " + transportation + " ]");
		try {
			// 模拟程序员到达目的地花费时间的随机性
			TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(10));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		latch.countDown();
		if (!latch.isLate)
			logger.info(programmer + " arrived on time!!!");
		if (latch.getUnarrived() == 0)
			logger.info("all the programmers arrived");
	}

	public static void main(String[] args) {
		// 设置阀门值为4,并标记未迟到
		Latch latch = new CountDownLatch(4, false);
		new ProgrammerTravel(latch, "Tom", "bike").start();
		new ProgrammerTravel(latch, "Selina", "bike").start();
		new ProgrammerTravel(latch, "King", "Car").start();
		new ProgrammerTravel(latch, "Khan", "Bus").start();
		try {
			// 设置预定时间为5秒
			latch.await(TimeUnit.SECONDS, 5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			System.err.println(e);
		}
	}

}

demo2-子线程任务完成之后执行主线程

重写runnable run(),使用java.util的CountDownLatch,实现多个子线程任务完成之后,执行主线程的任务。 

package com.mzs.demo1;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Logger;

public class CountDownLatchTest1 {
	
	private static Logger logger = Logger.getLogger("com.mzs.demo1.CountDownLatchTest1");
	
	public static void main(String[] args) {
		ExecutorService service = Executors.newFixedThreadPool(3);
		CountDownLatch latch = new CountDownLatch(3);
		for (int i = 0; i < 3; i++) {
			Runnable runnable = new Runnable() {

				@Override
				public void run() {
					logger.info("child thread [" + Thread.currentThread().getName() + "] starts to execute");
					try {
						Thread.sleep(ThreadLocalRandom.current().nextInt(20));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					logger.info("child thread [" + Thread.currentThread().getName() + "] finished");
					latch.countDown();
				}
			};
			service.execute(runnable);
		}
		logger.info("main thread [" + Thread.currentThread().getName() + "] is waiting");
		try {
			latch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		logger.info("main thread [" + Thread.currentThread().getName() + "] starts to execute");
	}

}

demo3-多个CountDownLatch的应用 

package com.mzs.demo1;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Logger;

public class CountDownLatchTest2 {
	
	private static Logger logger = Logger.getLogger("com.mzs.demo1.CountDownLatchTest2");
	
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		CountDownLatch latch = new CountDownLatch(1);
		CountDownLatch latch1 = new CountDownLatch(4);
		for (int i = 0; i < 4; i++) {
			Runnable runnable = new Runnable() {

				@Override
				public void run() {
					logger.info("运动员" + Thread.currentThread().getName() + "等待裁判命令");
					try {
						latch.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					logger.info("运动员" + Thread.currentThread().getName() + "接收裁判命令");
					try {
						Thread.sleep(ThreadLocalRandom.current().nextInt(20));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					logger.info("运动员" + Thread.currentThread().getName() + "到达终点");
					latch1.countDown();
				}
			};
			service.execute(runnable);
		}
		latch.countDown();
		try {
			latch1.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		logger.info("裁判" + Thread.currentThread().getName() + "评判结果");
	}
	
}

猜你喜欢

转载自blog.csdn.net/qq_34561892/article/details/83310291