java.util.concurrent小结

在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便。而当针对高质量Java多线程并发程序设计时,为防止死蹦等现象的出现,比如使用java之前的wait()、notify()和synchronized等,每每需要考虑性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的危害等诸多因素,往往会采用一些较为复杂的安全策略,加重了程序员的开发负担。

万幸的是,JDK1.5出现之后,Sun大神(Doug Lea)终于为我们这些可怜的小程序员推出了java.util.concurrent工具包以简化并发完成。开发者们借助于此,将有效的减少竞争条件(race conditions)和死锁线程。concurrent包很好的解决了这些问题,为我们提供了更实用的并发程序模型。

部分API类图如下:



实用类介绍

Semaphore

计数信号量,只对可用许可的号码进行计数,并采取相应的行动。Semephore通常用于限制可以访问某些资源的线程数目。acquire方法请求一个许可,有可用资源之前一直阻塞。release方法释放一个许可给Semaphore。这里是一个实际的情况,大家排队上厕所,厕所只有两个位置,来了10个人需要排队。

public class MySemaphore extends Thread {
	private int id;
	private Semaphore s;
	
	public MySemaphore(int id, Semaphore s) {
		this.id = id;
		this.s = s;
	}
	
	public void run() {
		if (s.availablePermits() > 0) 
			System.out.println("顾客[" + this.id + "]进入厕所,有空位");
		else 
			System.out.println("顾客[" + this.id + "]进入厕所,无空位");
		
		try {
			s.acquire();
			System.out.println("顾客[" + this.id + "]获得坑位");
			Thread.sleep((int)(Math.random() * 1000));
			System.out.println("顾客[" + this.id + "]使用完毕");
			s.release();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		Semaphore s = new Semaphore(2);
		ExecutorService service = Executors.newCachedThreadPool();
		for (int i=0; i<10; i++) {
			service.submit(new MySemaphore(i, s));
		}
		service.shutdown();
		s.acquireUninterruptibly(2);// 请求2个信号量,在2个信号量可用之前,一直阻塞
		System.out.println("使用完毕,需要清扫了");
		s.release(2);// 释放2个新号量给Semaphore
	}
}

CountDownLatch

同步辅助类。调用countDown(),在当前计数到达零之前,await()方法会一直阻塞。可以将初始化计数为1的CountDownLatch作为一个简单的开关锁存器。用初始化为N的CountDownLatch可以使一个线程在N个线程执行某项操作之前或者一个线程执行N次操作之前一直等待。

public class MyCountDownLatch {
	static final CountDownLatch begin = new CountDownLatch(2);
	static final CountDownLatch end = new CountDownLatch(10);
	
	public static void main(String[] args) throws InterruptedException {
		ExecutorService service = Executors.newFixedThreadPool(10);
		for (int i=0; i<10; i++) {
			final int number = i + 1;
			Runnable task = new Runnable() {
				
				@Override
				public void run() {
					try {
						begin.await();// 一直阻塞
						Thread.sleep((int)(Math.random() * 10000));
						System.out.println("NO." + (number + 1) + " arrived");
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						end.countDown();
					}
				}
			};
			service.submit(task);
		}
		
		System.out.println("Game start");
		begin.countDown();
		end.await();
		System.out.println("Game over");
		service.shutdown();
	}
}
注:上面调用begin.await()时一直阻塞。除非在调用await()方法之前,调用begin.countDown(),让计数到达零。

CyclicBarrier

同步辅助类。允许一组线程相互等待,直到达到一个公共屏障点。最重要的参数为参与者个数,创建对象时通过构造方法传入。另外重要的方法是await(),当所有参与者对应的线程都调用await()方法,这些线程都可以继续执行,否则就会等待。

public class MyCyclicBarrier {
	// 步行
	private static final int[] timeWalk = {5, 8, 15, 15, 10};
	// 自驾游
	private static final int[] timeSelf = {1, 3, 4, 4, 5};
	// 旅游大巴
	private static final int[] timeBus = {2, 4, 6, 6, 7};
	
	public static String now() {
		return new SimpleDateFormat("HH:mm:ss").format(new Date());
	}
	
	static class Tour extends Thread {
		private CyclicBarrier barrier;
		private String tourName;
		private int[] times;
		
		public Tour(CyclicBarrier barrier, String tourName, int[] times) {
			this.barrier = barrier;
			this.tourName = tourName;
			this.times = times;
		}
		
		public void run() {
			try {
				Thread.sleep(times[0] * 1000);
				System.out.println(now() + ": " + tourName + " reached ShenZhen");
				barrier.await();
				
				Thread.sleep(times[1] * 1000);
				System.out.println(now() + ": " + tourName + " reached GuangZhou");
				barrier.await();
				
				Thread.sleep(times[2] * 1000);
				System.out.println(now() + ": " + tourName + " reached ShaoGuan");
				barrier.await();
				
				Thread.sleep(times[3] * 1000);
				System.out.println(now() + ": " + tourName + " reached ChangSha");
				barrier.await();
				
				Thread.sleep(times[4] * 1000);
				System.out.println(now() + ": " + tourName + " reached WhHan");
				barrier.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		CyclicBarrier barrier = new CyclicBarrier(3);
		ExecutorService service = Executors.newFixedThreadPool(3);
		service.submit(new Tour(barrier, "WalkTour", timeWalk));
		service.submit(new Tour(barrier, "SelfTour", timeSelf));
		// 当我们把下面的程序注释了,会发现程序阻塞了,无法继续进行下去
		service.submit(new Tour(barrier, "BusTour", timeBus));
		service.shutdown();		
	}
}

ReentrantLock 

互斥锁定Lock,与synchronized方法和语句具有相同的基本行为和语义,但功能更强大。lock方法请求锁,若资源未锁定,则可以获取锁。unlock方法释放持有的锁资源。

public class MyReentrantLock extends Thread {
	private int id;
	private TestReentrantLock test;
	
	public MyReentrantLock(int id, TestReentrantLock test) {
		this.id = id;
		this.test = test;
	}
	
	public void run() {
		this.test.print(id);
	}
	
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		TestReentrantLock lock = new TestReentrantLock();
		for (int i=0; i<10; i++) {
			service.submit(new MyReentrantLock(i, lock));
		}
		service.shutdown();
	}
}

class TestReentrantLock {
	private ReentrantLock lock = new ReentrantLock();
	
	public void print(int id) {
		try {
			lock.lock();
			System.out.println(id + ", 获得!");
			Thread.sleep((int)(Math.random() * 1000));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println(id + ", 释放!");
			lock.unlock();
		}
	}
}
BlockingQueue

该接口是线程安全的,主要用于实现生产者-消费者队列。可以设置初始化大小,若不设置,默认Integer.MAX_VALUE。可以通过add(E)、put(E)、offer(E)添加元素,但添加元素不能为null,否则报NullPointerException。可以通过take()移除队列的头部元素。

public class MyBlockingQueue extends Thread {
	private static BlockingQueue<String> queue = new LinkedBlockingQueue<String>(3);
	private int id;
	
	public MyBlockingQueue(int id) {
		this.id = id;
	}
	
	public void run() {
		try {
			queue.put(String.valueOf(id));
			System.out.println("{" + id + "} in queque");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		for (int i=0; i<10; i++) 
			service.submit(new MyBlockingQueue(i));
		
		Runnable task = new Runnable() {
			
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep((int)(Math.random() * 1000));
						if (queue.isEmpty())
							break;
						System.out.println(queue.take() + " has take");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};
		service.submit(task);
		service.shutdown();
	}
}

CompletionService

将生产新的异步任务与已完成任务的结果分离开来的服务。submit方法提交一个Runnable任务执行,并返回一个Future代表任务。take()释放并移除代表下一个即将完成任务的Future。

public class MyCompletionService implements Callable<String> {
	private int id;
	
	public MyCompletionService(int id) {
		this.id = id;
	}
	
	@Override
	public String call() throws Exception {
		int time = (int)(Math.random() * 1000);
		
		try {
			System.out.println("{" + this.id + "}, 启动");
			Thread.sleep(time);
			System.out.println("{" + this.id + "}, 关闭");
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
		return this.id + "," + time;
	}
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService executor = Executors.newCachedThreadPool();
		final CompletionService<String> cs = new ExecutorCompletionService<String>(executor);
		for (int i=0; i<10; i++) {
			cs.submit(new MyCompletionService(i));
		}
		
		for (int i=0; i<10; i++)
			System.out.println(cs.take().get());
		executor.shutdown();
	}
	
}

ScheduledExecutorService

使用Executors的execute(Runnable)方法和ExecutorService的submit(Runnable)方法,提交的请求,为0延迟进行安排。所有schedule接受相对周期和延迟作为参数,ScheduledExecutorService提供了scheduleAtFixedRate 和 scheduleWithFixedDelay 方法创建并执行某些在取消前一直定期运行的任务。

public class TestSchedule {
	public static void main(String[] args) {
		final ScheduledExecutorService scheduleService = Executors.newScheduledThreadPool(2);
		final Runnable beeper = new Runnable() {
			int count = 0;
			@Override
			public void run() {
				System.out.println(new Date() + " beep " + (++count));
			}
		};
		// 1秒后运行,每隔两秒运行一次
		final ScheduledFuture beeperHandler = scheduleService.scheduleAtFixedRate(beeper, 1, 2, TimeUnit.SECONDS);
		// 2秒后运行,上次任务结束后等待5秒继续运行
		final ScheduledFuture beeperHandler2 = scheduleService.scheduleWithFixedDelay(beeper, 2, 5, TimeUnit.SECONDS);
		// 30秒后关闭schedule
		scheduleService.schedule(new Runnable() {
			
			@Override
			public void run() {
				beeperHandler.cancel(true);
				beeperHandler2.cancel(true);
			}
		}, 30, TimeUnit.SECONDS);
		scheduleService.shutdown();
	}
}

参考资料:http://www.open-open.com/bbs/view/1320131360999

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值