Synchronized和ReentrantLock

java synchronized知识点

synchronized相信学过java并发编程的小伙伴一定不会陌生,synchronized用来控制中线程的同步。
线程安全性:当多个线程同时访问一个类的(对象或者方法),这个类总是表现出正确的行为,则称这个类是线程安全的。

  • synchronized的含义
    1.互斥性
    synchronized用来修饰方法,代码块。
    修饰普通成员方法时,取得的对象锁是调用该方法的对象。
    修饰静态方法时,取得的对象锁是该类的class对象(存在于方jvm的方法区,只有一个)
    修饰代码块的时,对象锁需要开发者自行指定。注意:该对象一定要为共享的,不然线程不安全。
    2.内存可见性
    synchronzied除了互斥的含义之外,还有可见性的含义。
  • synchronized的特性
    1.可重入性
    重入的一种实现方法:为每一个锁关联一个计数值和一个所有者线程。当计数值为0的时候代表该锁不被任何线程持有。当一个线程请求一个未被持有的锁时,JVM将记下锁的持有者,并将计数值加一。当同一个线程再次获取这个锁的时候,计数值递增,当线程退出同步代码块的时候,计数器递减。当为0的时候,这个锁被释放。
    第一个例子:

public class UseSynchronized {
public synchronized void method1(){
System.out.println("进入方法1");
method2();
}
public synchronized void method2(){
System.out.println("进入方法2");
method3();
}
public synchronized void method3(){
System.out.println("进入方法3");
}
public static void main(String[] args) {
final UseSynchronized us=new UseSynchronized();
us.method1();
}
}
第二个例子:java
public class UseSynchronized {
private class A{
public synchronized void test(){
System.out.println("这是父类的方法");
}
}
class B extends A{
public synchronized void test(){
System.out.println("这是子类的方法");
super.test();
}
}
public static void main(String[] args) {
B b=new UseSynchronized().new B();
b.test();
}
}
```
2.悲观锁、独占锁
使用synchronized关键字来保证线程安全性的时候,将会使线程串行化调用方法或者执行代码块。这也就是一些同步类容器例如vector、hashtable效率不高的原因。

java ReentrantLock知识点

  • ReentrantLock的含义
    1.ReentrantLock与synchronized不同的地方在于它是一种显示锁,需要手动的lock,unlock,它有自己的condition
    2.ReentrantLock也是一种悲观锁

很多人认为ReentrantLock和synchronized比较,前者性能要比后者性能高很多,其实java1.8以后对synchronized性能进行了优化,使其和ReentrantLock的性能相差不多。

package org.lock;

import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

abstract class Accumulator{
    public static long cycles=50000L;
    private static final int N=5;
    public static ExecutorService exec=Executors.newFixedThreadPool(N*2);
    private static CyclicBarrier barrier=new CyclicBarrier(N*2+1);
    protected volatile int index=0;
    protected volatile long value=0;
    protected long duration=0;
    protected String id="error";
    protected final static int SIZE=100000;
    protected static int[] preLoaded=new int[SIZE];
    static{
        Random rand=new Random(47);
        for(int i=0;i<SIZE;i++){
            preLoaded[i]=rand.nextInt();
        }
    }
    public abstract void accumulate();
    public abstract long read();
    private class Modifier implements Runnable{
        @Override
        public void run() {
            for(long i=0;i<cycles;i++){
                accumulate();
            }
            try {
                barrier.await();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    private class Reader implements Runnable{
        @Override
        public void run() {
            for(long i=0;i<cycles;i++){
                value=read();
            }
            try {
                barrier.await();
            } catch (Exception e) {
                throw new RuntimeException(e);
            } 
        }
    }
    public void timeTest(){
        long start=System.nanoTime();
        for(int i=0;i<N;i++){
            exec.execute(new Modifier());
            exec.execute(new Reader()); 
        }
        try {
            barrier.await();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        duration=System.nanoTime()-start;
        System.out.println(id+"----"+duration);
    }
    public static void report(Accumulator acc1,Accumulator acc2){
        System.out.println(acc1.id+"/"+acc2.id+"="+(double)acc1.duration/(double)acc2.duration);
    }
}
class BaseLine extends Accumulator{
    {
        id="BaseLine";
    }

    @Override
    public void accumulate() {
        value+=preLoaded[index++];
        if(index>=SIZE){
            index=0;
        }
    }

    @Override
    public long read() {
        return value;
    }
}
class SynchronizedTest extends Accumulator{
    {
        id="synchronized";
    }

    @Override
    public synchronized void accumulate() {
        value+=preLoaded[index++];
        if(index>=SIZE){
            index=0;
        }
    }

    @Override
    public synchronized long read() {
        return value;
    }
    
}
class LockTest extends Accumulator{
    {
        id="Lock";
    }
    private Lock lock=new ReentrantLock();
    
    @Override
    public void accumulate() {
        lock.lock();
        try{
            value+=preLoaded[index++];
            if(index>=SIZE){
                index=0;
            }
        }finally{
            lock.unlock();
        }
    }

    @Override
    public long read() {
        lock.lock();
        try{
            return value;
        }finally{
            lock.unlock();
        }
    }
}
public class SynchronizationComparisons {
    static SynchronizedTest synch=new SynchronizedTest();
    static LockTest lock=new LockTest();
    static void test(){
        System.out.println("==========================");
        System.out.println("Cyccle"+"  "+Accumulator.cycles);
        synch.timeTest();
        lock.timeTest();
        Accumulator.report(synch, lock);
    }
    public static void main(String[] args) {
        int iterations=5;
        if(args.length>0){
            iterations=new Integer(args[0]);
        }
        System.out.println("Warmup");
        for(int i=0;i<iterations;i++){
            test();
            Accumulator.cycles*=2;
        }
        Accumulator.exec.shutdown();
    }
}

运行结果:


两种锁性能比较.png

从运行结果可以看出,ReentrantLock性能比Synchronized好一点,但也好不太多。(运行环境:JDK1.8)

ReentrantLock之所以比synchronized好的地方在于不是它的性能,而是它的多condition,这是synchronized不能比较的。例如ArrayBlockingQueue中就是用的ReentrantLock,里面有两个condition

condition.png

总结:并不是所有的地方的都适合用ReentrantLock,具体使用什么要根据生产环境确定。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容