Java理论与实践: 风行的原子[Java编程]
本文“Java理论与实践: 风行的原子[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
十五年前,多处理器系统是高度专用系统,要耗费数十万美圆(大大都具有 两个到四个处理器).目前,多处理器系统很便宜,并且数目很多,几近每个主 要微处理器都内置了多处理支持,此中很多系统支持数十个或数百个处理器.
要利用多处理器系统的功效,普通需求利用多线程构造利用程序.但是正如 任何编写并发利用程序的人可以奉告你的那样,要得到好的硬件操纵率,只是简 单地在多个线程中分割工作是不够的,还必须确保线程确切大部份时间都在工作 ,而不是在等候更多的工作,或等候锁定同享数据构造.
问题:线程之间的调和
假如线程之间 不需求调和,那么几近没有任务可以真正地并行.以线程池为 例,此中履行的任务普通彼此独立.假如线程池操纵大众工作行列,则从工作队 列中删除元素或向工作行列增添元素的历程必须是线程安全的,并且这意味着要 调和对头、尾或节点间链接指针所举行的拜候.恰是这种调和招致了全部问题.
尺度办法:锁定
在 Java 语言中,调和对同享字段的拜候的传统办法是利用同步,确保完成 对同享字段的全部拜候,同时具有得当的锁定.通过同步,可以肯定(假定类编 写精确)具有保护一组给定变量的锁定的全部线程都将拥有对这些变量的独占访 问权,并且今后其他线程得到该锁按时,将可以看到对这些变量举行的更改.弊 端是假如锁定竞争太利害(线程常常在其他线程具有锁按时要求得到该锁定), 会侵害吞吐量,因为竞争的同步非常高贵.(Public Service Announcement: 关于现代 JVM 而言,无竞争的同步目前非常便宜.
基于锁定的算法的另一个问题是:假如耽误具有锁定的线程(因为页面错误 、筹划耽误或其他意料之外的耽误),则 没有要求得到该锁定的线程可以持续 运行.
还可以利用可变变量来以比同步更低的本钱存储同享变量,但它们有范围性 .固然可以保证其他变量可以当即看到对可变变量的写入,但无法显现原子操作 的读-改正-写次序,这意味着(比方说)可变变量无法用来坚固地实现互斥(互 斥锁定)或计数器.
利用锁定实现计数器和互斥
假定开辟线程安全的计数器类,那么这将表露 get()、 increment() 和 decrement() 操作.清单 1 显示了若何利用锁定(同步)实现该类的例子.注 意全部办法,乃至需求同步 get(),使类成为线程安全的类,从而确保没有任何 更新信息丧失,全部线程都看到计数器的最新值.
清单 1. 同步的计数器类
public class SynchronizedCounter {
private int value;
public synchronized int getValue() { return value; }
public synchronized int increment() { return ++value; }
public synchronized int decrement() { return --value; }
}
increment() 和 decrement() 操作是原子的读-改正-写操作,为了安全实现 计数器,必须利用当前值,并为其增添一个值,或写出新值,全部这些均视为一 项操作,其他线程不能打断它.不然,假如两个线程试图同时履行增添,操作的 不幸穿插将招致计数器只被实现了一次,而不是被实现两次.(注意,通过使值 实例变量成为可变变量并不能坚固地完成这项操作.)
很多并发算法中都显示了原子的读-改正-写组合.清单 2 中的代码实现了简 单的互斥, acquire() 办法也是原子的读-改正-写操作.要得到互斥,必须确 保没有其他人具有该互斥( curOwner = Thread.currentThread()),然后记录 您拥有该互斥的事实( curOwner = Thread.currentThread()),全部这些使其 他线程不大概在中间呈现以及改正 curOwner field.
清单 2. 同步的互斥类
public class SynchronizedMutex {
private Thread curOwner = null;
public synchronized void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException ();
while (curOwner != null)
wait();
curOwner = Thread.currentThread();
}
public synchronized void release() {
if (curOwner == Thread.currentThread()) {
curOwner = null;
notify();
} else
throw new IllegalStateException("not owner of mutex");
}
}
清单 1 中的计数器类可以坚固地工作,在竞争很小或没有竞争时都可以很好 地履行.但是,在竞争激烈时,这将大大侵害性能,因为 JVM 用了更多的时间 来调度线程,管理竞争和等候线程行列,而实际工作(如增添计数器)的时间却 很少.您可以回想 上月专栏中的图,该图显示了一旦多个线程利用同步竞争一 个内置监督器,吞吐量将若何大幅度下降.固然该专栏阐明了新的 ReentrantLock 类若何可以更可伸缩地替换同步,但是关于一些问题,还有更好 的办理办法.
以上是“Java理论与实践: 风行的原子[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |