5.0的多线程任务包对于同步的性能方面有了很大的改进,在原有synchronized关键字的基础上,又增加了ReentrantLock,以及各种Atomic类。了解其性能的优劣程度,有助与我们在特定的情形下做出正确的选择。

总体的结论先摆出来:

synchronized: 
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

ReentrantLock: 
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

Atomic: 
和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。

所以,我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。

先贴测试结果:再贴代码(Atomic测试代码不准确,一个同步中只能有1个Actomic,这里用了2个,但是这里的测试只看速度) 
========================== 
round:100000 thread:5 
Sync = 35301694 
Lock = 56255753 
Atom = 43467535 
========================== 
round:200000 thread:10 
Sync = 110514604 
Lock = 204235455 
Atom = 170535361 
========================== 
round:300000 thread:15 
Sync = 253123791 
Lock = 448577123 
Atom = 362797227 
========================== 
round:400000 thread:20 
Sync = 16562148262 
Lock = 846454786 
Atom = 667947183 
========================== 
round:500000 thread:25 
Sync = 26932301731 
Lock = 1273354016 
Atom = 982564544

Java代码

package test.thread;   

import static java.lang.System.out;   

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock; public class TestSyncMethods { public static void test(int round,int threadNum,CyclicBarrier cyclicBarrier){
new SyncTest("Sync",round,threadNum,cyclicBarrier).testTime();
new LockTest("Lock",round,threadNum,cyclicBarrier).testTime();
new AtomicTest("Atom",round,threadNum,cyclicBarrier).testTime();
} public static void main(String args[]){ for(int i=0;i<5;i++){
int round=100000*(i+1);
int threadNum=5*(i+1);
CyclicBarrier cb=new CyclicBarrier(threadNum*2+1);
out.println("==========================");
out.println("round:"+round+" thread:"+threadNum);
test(round,threadNum,cb); }
}
} class SyncTest extends TestTemplate{
public SyncTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){
super( _id, _round, _threadNum, _cb);
}
@Override
/**
* synchronized关键字不在方法签名里面,所以不涉及重载问题
*/
synchronized long getValue() {
return super.countValue;
}
@Override
synchronized void sumValue() {
super.countValue+=preInit[index++%round];
}
} class LockTest extends TestTemplate{
ReentrantLock lock=new ReentrantLock();
public LockTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){
super( _id, _round, _threadNum, _cb);
}
/**
* synchronized关键字不在方法签名里面,所以不涉及重载问题
*/
@Override
long getValue() {
try{
lock.lock();
return super.countValue;
}finally{
lock.unlock();
}
}
@Override
void sumValue() {
try{
lock.lock();
super.countValue+=preInit[index++%round];
}finally{
lock.unlock();
}
}
} class AtomicTest extends TestTemplate{
public AtomicTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){
super( _id, _round, _threadNum, _cb);
}
@Override
/**
* synchronized关键字不在方法签名里面,所以不涉及重载问题
*/
long getValue() {
return super.countValueAtmoic.get();
}
@Override
void sumValue() {
super.countValueAtmoic.addAndGet(super.preInit[indexAtomic.get()%round]);
}
}
abstract class TestTemplate{
private String id;
protected int round;
private int threadNum;
protected long countValue;
protected AtomicLong countValueAtmoic=new AtomicLong(0);
protected int[] preInit;
protected int index;
protected AtomicInteger indexAtomic=new AtomicInteger(0);
Random r=new Random(47);
//任务栅栏,同批任务,先到达wait的任务挂起,一直等到全部任务到达制定的wait地点后,才能全部唤醒,继续执行
private CyclicBarrier cb;
public TestTemplate(String _id,int _round,int _threadNum,CyclicBarrier _cb){
this.id=_id;
this.round=_round;
this.threadNum=_threadNum;
cb=_cb;
preInit=new int[round];
for(int i=0;i<preInit.length;i++){
preInit[i]=r.nextInt(100);
}
} abstract void sumValue();
/*
* 对long的操作是非原子的,原子操作只针对32位
* long是64位,底层操作的时候分2个32位读写,因此不是线程安全
*/
abstract long getValue(); public void testTime(){
ExecutorService se=Executors.newCachedThreadPool();
long start=System.nanoTime();
//同时开启2*ThreadNum个数的读写线程
for(int i=0;i<threadNum;i++){
se.execute(new Runnable(){
public void run() {
for(int i=0;i<round;i++){
sumValue();
} //每个线程执行完同步方法后就等待
try {
cb.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
});
se.execute(new Runnable(){
public void run() { getValue();
try {
//每个线程执行完同步方法后就等待
cb.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
});
} try {
//当前统计线程也wait,所以CyclicBarrier的初始值是threadNum*2+1
cb.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//所有线程执行完成之后,才会跑到这一步
long duration=System.nanoTime()-start;
out.println(id+" = "+duration); } }

原文url:http://blog.csdn.net/gonxi/article/details/7715867

 
 自己看了一下Automic累加方法的源码,加完之后有一个比较的操作,看不到源码只能从方法的注释里面找答案了:
每次加完之后都会看一下内存里面是不是自己的期望值,如果是期望值就return,如果不是就重新获取内存里的值到寄存器,再次进行累加操作。
 

各种同步方法性能比较(synchronized,ReentrantLock,Atomic)的更多相关文章

  1. 各种同步方法性能比较(synchronized,ReentrantLock,Atomic)

    synchronized: 在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的.原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不 ...

  2. java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析

    java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...

  3. 并发编程之ThreadLocal、Volatile、synchronized、Atomic关键字扫盲

    前言 对于ThreadLocal.Volatile.synchronized.Atomic这四个关键字,我想一提及到大家肯定都想到的是解决在多线程并发环境下资源的共享问题,但是要细说每一个的特点.区别 ...

  4. ThreadLocal、Volatile、synchronized、Atomic

    前言 对于ThreadLocal.Volatile.synchronized.Atomic这四个关键字,我想一提及到大家肯定都想到的是解决在多线程并发环境下资源的共享问题,但是要细说每一个的特点.区别 ...

  5. synchronized,ReentrantLock解决锁冲突,脏读的问题

    最常见的秒杀系统,解决思路就是从前端.后台服务.数据库层层去掉负载,以达到平衡 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLo ...

  6. synchronized ReentrantLock 比较分析

    在编写多线程代码的时候,对于不允许并发的代码,很多需要加锁进行处理.在进行加锁处理时候,synchronized作为java的内置锁,同时也是java关键字,最为被人熟知,即使是最初级的java程序员 ...

  7. 还在用Synchronized?Atomic你了解不?

    前言 只有光头才能变强 之前已经写过多线程相关的文章了,有兴趣的同学可以去了解一下: https://github.com/ZhongFuCheng3y/3y/blob/master/src/thre ...

  8. Java性能之synchronized锁的优化

    synchronized / Lock 1.JDK 1.5之前,Java通过synchronized关键字来实现锁功能 synchronized是JVM实现的内置锁,锁的获取和释放都是由JVM隐式实现 ...

  9. java 多线程实现四种方式解析Thread,Runnable,Callable,ServiceExcutor,Synchronized ,ReentrantLock

    1.Thread实现: import java.util.Date; import java.text.SimpleDateFormat; public class MyThread extends ...

随机推荐

  1. 二维数组 string[,]

    string[,] strArr = {                               {"101","电脑"},                 ...

  2. iOS设计模式之原型模式

    原型模式 基本理解 原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节 ...

  3. Android线程管理(二)——ActivityThread

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  4. Objective-C之@class的使用

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  5. js事件执行顺序

    http://ejohn.org/blog/how-javascript-timers-work/

  6. mysql由浅入深探究(一)----数据库简介与mysql安装

    mysql简介: 首先谈到mysql,我们要知道这是一个开源的数据库,与开源对应的就是free,但这并不意味着其性能会比很差,mysql同样能支持千万级以上的大数据量,甚至更多.同时mysql还支持许 ...

  7. nginx的配置总结

    总体而言,nginx的配置比起apache来是要简洁很多,而言容易理解得多的,另外官网的文档也十分的简洁易懂.我们先看一个简化版的配置文件nginx.conf: #user nobody; worke ...

  8. Ubuntu文本编辑时vi和nano命令的区别(建议使用nano)

    vi是Unix世界里极为普遍的全荧幕文书编辑器,几乎可以说任何一台Unix机器都会提供这套软体就像windows的记事本一样. 键入 vi /etc/hosts 进入vi界面,把光标移动到文件未尾.按 ...

  9. ASP.NET中常用的几个李天平开源公共类LTP.Common,Maticsoft.DBUtility,LtpPageControl (转)

    ASP.NET中常用的几个开源公共类: LTP.Common.dll: 通用函数类库     源码下载Maticsoft.DBUtility.dll 数据访问类库组件     源码下载LtpPageC ...

  10. k-means算法初识

    基础知识: K-means聚类算法 聚类,简单地说就是把相似的东西分到一组.同 Classification (分类)不同,对于一个 classifier ,通常需要你告诉它“这个东西被分为某某类”. ...