Java Synchronized

一、为什么需要锁

存在共享数据。
当出现ConcurrentModificationException的时候,存在多个线程对一个集合同时进行遍历或者修改。
单线程就不需要考虑这种情况。

二、解决方案

当前类中涉及集合修改和遍历操作加上synchronized关键字,或者是这两个逻辑放在一个线程中完成。

1、可重入&&互斥

synchronized是可重入锁;ReentrantLock也是。
即同一个线程可以输出Hello World不会死锁。

    // 可重入
    public void syncsTask() {
        synchronized (this) {
            System.out.println("Hello");
            synchronized (this){
                System.out.println("World");
            }
        }
    }

synchronized是互斥锁,满足互斥性(操作的原子性),可见性。
synchronized锁的不是代码,是对象。
同步代码块synchronized(this)和同步方法锁的是同一个对象。
类锁和对象锁是互不干扰的。只有使用同一把锁线程之间才会干扰。
Java对象头中都存在一个Monitor对象,这也是Java中任意对象可以作为锁的原因。

2、为什么很多人对它嗤之以鼻

早前版本是重量级锁,依赖于系统的Mutex Lock(互斥),线程之间切换从用户态转换至核心态,开销大。
jdk6之后性能已经提升。

3、自旋锁与自适应自旋锁

jdk6默认开启,不挂起线程,但如果锁占用时间过长,就不再推荐使用了。
让线程处于忙循环等待锁释放,不出让CPU,减少线程的切换。

4、锁消除

JIT编译时,对运行上下文进行扫描,去除不可能存在竞争的锁。

5、锁粗化

JVM对锁的范围进行扩大,减少锁同步的代价。

6、synchronized的四个演变阶段

锁膨胀的方向:无锁、偏向锁、轻量级锁、重量级锁
偏向锁:CAS,指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价
轻量级锁:偏向锁升级而来,适用于线程交替执行同步块,自旋
重量级锁:同步块或者方法执行时间较长,追求吞吐量


对象头不同阶段的演变

三、synchronized和static synchronized区别

一个锁的是类对象,一个锁的是实例对象。
若类对象被lock,则类对象的所有同步方法(static synchronized 修饰)全被lock;
若实例对象被lock,则该实例对象的所有同步方法(synchronized 修饰)全被lock。
每个synchronized方法都必须获得调用该方法的类实例的”锁“方能执行,否则所属线程阻塞。

方法一旦执行,就会独占该锁,一直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,从而重新进入可执行状态。这种机制确保了同一时刻对于每一个类的实例,其所有声明为synchronized的成员函数中之多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突。

四、synchronized方法与synchronized代码块

    private synchronized void syncFunc() {
        // do something
    }

    private void syncBlockFunc() {
        synchronized (this) {
            // do something
        }
    }

synchronized methods() {}与synchronized(this){}之间没有什么区别,只是synchronized methods() {} 便于阅读理解,而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。

五、synchronized和ReentrantLock区别

所属不同关键字,类。
底层实现不同MarkWord,Unsafe类。
ReentrantLock可以选择公平(fair)锁(排队打饭)和非公平锁,构造函数传入true;
synchronized是非公平的(堵车时的加塞)。

// 一般通常会使用try catch finally方式
public class ReentrantLockDemo implements Runnable {
    private static ReentrantLock lock = new ReentrantLock(false);

    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + " get lock");
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
                break;
            } finally {
                lock.unlock();
            }
        }
    }

将synchronized转换为直观可控的对象行为。

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

推荐阅读更多精彩内容