俗话说“工欲善其身,必先利其器”。要想编写好的多线程并发系统,就必须要有一些好的封装类来作为我们的sychironiziton aid。java.util.concurrent包下面就有许多封装好了的类用来帮助我们写好多线程并发系统的新工具。
一,原子类:java.util.concurrent.atomic
AtomicInteger,AtomicLong,AtomicBoolean,AtomicReference。它们的语义基本上和volatile一样,只不过封装在一个API了,这个API包含为操作提供的适当的原子方法(要么全做要么不做)。在编写这些实现时利用了现代处理器的特性,所以如果能从硬件和操作系统上得到适当的支持,它们可以是非阻塞(无须线程锁)的。如在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字,在AtomicInteger或AtomicLong上的原子操作getAndIncrement()方法就解决了这个问题。
注:原子类不是从有相似名称的类继承下来的,所以AtomicBoolean不能当Boolean用。
二,线程锁:java.util.concurrent.locks
sychronized同步方式是基于锁这样一个简单的概念,这种方式有几个缺点:
- 锁只有一种类型
- 对被锁住对象的所以同步操作都是一样的作用
- 在同步代码块或方法开始时取得线程锁,结束时释放线程锁
- 线程或者得到锁,或者阻塞-没有其他可能
如果我们重构对线程锁的支持,有几处可以得到提升(这就是Lock出现的原因吧):
- 添加不同类型的锁
- 对锁的阻塞没有限制,即允许在一个方法中上锁,在另一个方法中解锁
- 如果线程得不到锁,就允许线程后退或继续执行
- 允许线程尝试取锁,并可以在超过等待时间后放弃
Lock接口的几个实现类:
- ReentrantLock:本质上跟用在同步块上那种锁是一样的,但是它稍微灵活点。
- ReentrantReadWriteLock.ReadLock(静态内部类)
- ReentrantReadWriteLock.WriteLock(静态内部类)
Lock类的具体用法可以上网查查和看看帮助文档,这里就不写了。
三,CountDownLatch
JDK1.5 API 中文版的解释是:“一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。”想了一会儿还是觉得不好理解,于是看了看英文版的解释,英文是这样解释的:“A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.” 才发现又是中文翻译的不到位(还是我理解能力不好?)...直接简单的解释就是:CountDownLatch 可以让一个或者多个线程一直处于等待状态,直到其它线程完成各自的操作之后,一个或者多个线程才开始运行。
具体用法可以查看帮助文档下面是一个例子(来自其它博客):
public class CountDownLatchTest { // 模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。 public static void main(String[] args) throws InterruptedException { // 开始的倒数锁 final CountDownLatch begin = new CountDownLatch(1); // 结束的倒数锁 final CountDownLatch end = new CountDownLatch(10); // 十名选手 final ExecutorService exec = Executors.newFixedThreadPool(10); for (int index = 0; index < 10; index++) { final int NO = index + 1; Runnable run = new Runnable() { public void run() { try { // 如果当前计数为零,则此方法立即返回。 // 等待 begin.await(); Thread.sleep((long) (Math.random() * 10000)); System.out.println("No." + NO + " arrived"); } catch (InterruptedException e) { } finally { // 每个选手到达终点时,end就减一 end.countDown(); } } }; exec.submit(run); } System.out.println("Game Start"); // begin减一,开始游戏 begin.countDown(); // 等待end变为0,即所有选手到达终点 end.await(); System.out.println("Game Over"); exec.shutdown(); } }
三,ConcurrentHashMap,CopyOnWriteArrayList
ConcurrentHashMap类是标准HashMap的并发版本。它改进了Collections类中提供的SychironizedMap()功能,因为那些方法返回的集合中包含的锁要比需要的多。
CopyOnWriteArrayList的用法请参考Java中的CopyOnWrite容器 感觉写的比较好。
四,Queue
Java中有些多线程编程模式在很大程度上都依赖于Queue实现 线程的安全性。Queue常用来在线程之间传递工作单元,这个模式通常适合用Queue最简单的并发扩展BlockingQueue来实现。
1.BlockingQueue
BlockingQueue的两个特性:
- 向Queue中put()时,如果Queue以满,则放入的线程将等待直到Queue腾出了空间
- 从Queue中take()时,如果Queue为空,则会导致取出线程阻塞
BlockingQueue接口的两个基本实现:LinkedBlockingQueue,ArrayBlockingQueue.它们的特性以及使用场景就不说了,看名字就知道了。
2.使用工作单元
比如说,你有一个表示工作单元的MyAwesomeClass类,想要用多线程方式处理,你可能会想到用BlockingQueue<MyAwesomeClass>来表示工作队列。但是请想想用BlockingQueue<WorkUnit<MyAwesomeClass>>这样会不会更好呢(WorkUnit这个名字随便自己怎么取)?
public class WorkUnit<T> private final T workunit; public WorkUnit(T workUnit){ this.workunit=workUnit } public T getWork(){ return workunit; }
有了这层间接引用(有没有感觉有点Proxy模式的味道?),不用修改原来的类(这里就是MyAwesomeClass)就可以添加额外的数据或者处理方法了如:
- 测试(记录一个对象的修改历史)
- 性能指标(比如到达时间或者服务质量)
- 运行时系统信息
一个BlockingQueue + workunit的例子:
package concurrent.blockingQueue; public abstract class Pet { protected final String name; public Pet(String name) { super(); this.name = name; } public abstract void examine(); } class Cat extends Pet{ public Cat(String name) { super(name); } @Override public void examine() { System.out.println("Meow!"); } } class Dog extends Pet{ public Dog(String name) { super(name); } @Override public void examine() { System.out.println("Woof!"); } }
package concurrent.blockingQueue; //workUnit public class Appointment<T> { private final T toBeSeen; public T getPatient() { return toBeSeen; } public Appointment(T toBeSeen) { this.toBeSeen = toBeSeen; } }
package concurrent.blockingQueue; import java.util.concurrent.BlockingDeque; public class Veterinarian extends Thread { protected final BlockingDeque<Appointment<Pet>> appts; protected String text=""; protected final int restTime; private boolean shutdown=false; public Veterinarian(BlockingDeque<Appointment<Pet>> appts, int restTime) { super(); this.appts = appts; this.restTime = restTime; } public synchronized void shutdown(){ shutdown=true; } public void run(){ while(!shutdown){ this.seePatient(); try { Thread.sleep(restTime); } catch (Exception e) { shutdown=true; } } } public void seePatient(){ try { Appointment<Pet> ap=appts.take(); Pet patient=ap.getPatient(); patient.examine(); } catch (Exception e) { shutdown=true; } } }
除了简单的take()和offer() API ,BlockingQueue还提供了另外一种与队列交互的方式,这种控制力度更大。就是带有超时放入或者取出的操作,它还允许线程在遇到问题时可以从与队列的交互中退出来,转而做点其它的事情。
以上内容全部总结与《Java程序员修炼之道》如果想要具体,深入的了解建议看看原书。
相关推荐
EJB 技术是在 Java Bean 本地构件基础上,进展的面对服务器端分布应用构件技术,基于 Java 语言,供应了基于 Java 二进制字节代码的重用方式。EJB 给出了系统的服务器端分布构件规范,包括了构件、构件容器的接口...
这是控制并发访问的一种简单策略,但在复杂的应用中,可能需要更精细的同步机制,比如使用synchronized关键字或java.util.concurrent包中的工具类。 5. Thread生命周期 文档中的代码涉及到了线程的生命周期管理,...
在IT行业中,构件模型(Component Model)是一种软件开发方法,它允许开发者将应用程序分解为可重用的、独立的功能单元,这些单元被称为构件。构件模型促进了软件的模块化,提高了开发效率,降低了维护成本,同时也...
分布式计算在现代软件开发中扮演着重要角色,尤其是在大数据处理、云计算和互联网服务等领域。Java作为一门广泛应用的编程语言,提供了丰富的工具和框架来支持分布式计算。本篇将深入探讨基于Java的分布式计算构件库...
1. **企业JavaBeans(EJB):** EJB是Java EE中的一种构件模型,它提供了组件级别的服务,如事务管理、安全性、并发控制等。 2. **Java Servlets和JavaServer Pages(JSP):** 这些技术用于构建动态网页和Web应用...
这些新特性的介绍帮助读者了解和掌握最新Java版本的变化,使他们能够编写与现代Java标准兼容的代码。 书中还包含了大量的练习题和实际案例分析,这些都是加深理解和应用知识的重要手段。许多读者反馈说,书中的练习...
EJB是Java企业级应用的组成部分,它定义了组件模型,如会话bean、实体bean和消息驱动bean,提供了事务管理、安全性、并发控制等功能,使得开发者可以方便地构建分布式、事务处理的系统。 总的来说,软件复用与构件...
Java 企业级应用程序开发是构建大规模、高可用性、分布式系统的关键技术,而J2EE(Java 2 Platform, Enterprise Edition)和UML(统一建模语言)则是这个领域中的两个核心工具。J2EE是Java平台的一个版本,专注于...
本书是Java技术权威指南,全面覆盖Java技术的高级主题,包括流与文件、XML、网络、数据库编程、高级Swing、高级 AWT、JavaBean构件、安全、分布式对象、脚本、编译与注解处理等,同时涉及本地化、国际化以及Java SE ...
1. **多线程机制**:Java支持多线程,这意味着程序可以在多个线程上同时运行,提高了程序的并发执行能力。多线程是Java程序并行机制的一个重要体现,它允许开发者编写能够同时执行多个任务的应用程序。 2. **字符流...
本教程研究了线程的基础知识 — 线程是什么、线程为什么有用以及怎么开始编写... <br>我们还将研究更复杂的、使用线程的应用程序的基本构件 — 如何在线程之间交换数据、如何控制线程以及线程如何互相通信。
JAVA EE(Java Platform, Enterprise Edition)则是一个用于构建企业级应用的开放标准平台,由一系列服务、APIs和协议组成,如Servlet、JSP和EJB等构件。 CORBA(Common Object Request Broker Architecture)是一...
Java允许开发者创建多个线程,这些线程可以在单个程序中并发执行,从而实现并行处理任务,提高程序的效率。 Character流和Byte流是Java中的两种基本I/O流。它们的区别在于处理数据的基本单位不同,Character流以...
在电子商务环境中,Java 7的并发库有助于优化多用户访问场景下的性能,而try-with-resources则有助于资源管理,避免了手动关闭数据库连接等资源可能导致的泄露问题。 在【压缩包子文件的文件名称列表】:ePortal中...
2.4.2 基本成员默认值 2.5 方法、参数和返回值 2.5.1 参数列表 2.6 构建一个Java程序 2.6.1 名字可见性 2.6.2 运用其他构件 2.6.3 static 关键字 2.7 你的第一个J ava程序 编译和运行 2.8 注释和嵌入式文档 2.8.1 ...