synchronized和volatile实现原理

1)只有锁抢占时,才BlockED,如:synchronized方法,t1获得了锁,t2返回的状态则是Blocked

2)waiting:
    wait
    join
    LockSupport.park

3)jps: 显示所有的Java进程

4)jstack 848700(线程id)

5)start:
    start-->start这个是native方法


------------------------多线程原理分析------------------------
1)线程安全问题:
    比如:i++:
        单线程下没有问题。
        多线程下:2个线程同时访问,是先get i,再++,如果同时拿到了0,则 <=2;

2)线程安全性:
    管理对数据状态的访问:
        数据一定是共享的。
        数据在生命周期里,一定会变化。 像final,除了构造函数,则没机会修改。

3)一个线程去更新的时候,拿到的值在于并不是上一次线程更新后的值。

4)分布式锁

5)锁--》互斥: synchronized
    1.6偏向锁,轻量级锁的概念,对锁进行了性能优化。 既要保证锁的安全性,又要保证性能。


    1.修改实例方法

    只锁定当前实例,对象锁
    public synchronized void test(){

    }

    和上面的一样,但是锁的力度不一样
    public  void test(){
        synchronized(this){

        }
    }

    类级别的
    public synchronized static void test(){

    }

    类级别的
    public  static void test(){
        synchronized(Demo.class){

        }
    }


    2.修饰静态方法

    3.修饰代码块


    对象的生命周期决定的

    数据库:
        行锁
        表锁

    对象锁、类锁: 去呗字啊与是否跨对象跨线程被保护

    类锁:只有一个。 伴随着进程的生命周期结束和启动的。


    setNx(key, value): 0/1的互斥结果。多个进程设置时,只能设置成功一个。数据的存储和互斥

    对象在jvm中存储,会有一个内存布局:
        对象头:
            age
            锁标记
            偏向锁标记
            。。。

        实例数据

        填充数据

6)synchronized
    不同锁的类型
    什么时候触发各种锁


    无锁状态:对象的HashCode + 对象分代年龄+ 状态位001 
    GC标记
    轻量级锁: 只想栈中锁记录的指针。

    锁是可以升级的

    共享:多个对象都能访问到
    互斥:互斥特性,只有一个线程能访问

    对象头: MarkWord

    instanceOop

    无锁--》CAS偏向锁--》轻量级锁--》重量级锁:
        加锁保证安全性的同时,还要保证性能。 因此会有这几种锁。是锁住小区大门,还是自己家的门。
        1.6之前是重量级锁。是直接把线程挂起来。涉及到os内核进行线程上下文切换。

    还有一种,无锁化:


    有3种可能:
        只有线程A去访问(大部分情况是属于这种):
            HotStop作者发现大部分是这种,因此引入了偏向锁。
                A的ThreadID,偏向锁标记1,
                我们最后一定会关闭偏向锁。

        A和B交替访问。
            A拿到后,此时是偏向锁。  
            B接着去尝试获得锁,获取失败。 这时,就升级为轻量级锁(自旋)。
                B如果还获取不成功,那么只能让B线程阻塞。而1.6之前,则直接就是挂起。

        多个线程同时访问。
            最后只能升级到:阻塞状态。动口解决不了,只好动手。

7)偏向锁
    CAS比较实现原子性

    不能直接通过if比较

    乐观锁
        CompareAndSwap(value, expect, update):
            DB中通过version字段,

            MarkWord(32位):
                ThreadID(23)   epoch(2)    age(4)     1(1)     01(2)


    撤销偏向锁,升级为轻量级锁,从而接下来2个线程竞争将以轻量级锁的方式去竞争

    前提:
        大部门都是只有一个线程去访问。

8)1.6之前是重量级锁,为了优化性能,最开始最好肯定是不加锁。
    
    hotspot作者发现了实际情况,从最基本的锁开始,就想到用升级的过程去提升性能,

    最开始就是:没有锁,同时又实现数据安全性,然后就出现了偏向锁的概念,偏向锁是一般都是一个锁去访问到共享数据,

    然后继续真的有线程竞争了,就不断出现锁的升级去解决问题: 偏向锁--》轻量级锁--》重量级锁

9)轻量级锁 CAS: 自旋
    通过无意义的循环,去判断

    boolean cas(){
        if(flag){
        ....
            return; // 获取锁成功
        }
    }

    前提: 大部分的线程在获取锁之后,在非常短的时间会去释放锁。  而:如果直接让线程阻塞,那开销就大。

    自旋会浪费CPU资源,如果经历了一定的时间或者次数,还没有获得锁,那么轻量级锁就会升级为:重量级锁。也就是阻塞起来,就安静了。

    自旋次数:
        设置自旋次数 preBlockSpin
        自适应自旋

    MarkWord:    
        LockRecord

10)重量级锁:
    升级到重量级锁后,没有获得锁的线程,将会变为BLOCKED状态,重量级锁是基于监视器来实现的。 ObjectMonitor。 所以任何对象都可以成为锁。
    monitor是基于MutexLock(互斥锁)--》如果monitorrenter成功,则说明获得了锁,系统级别的线程切换(内核态  用户态)
        同步队列(每一个被阻塞的线程,会被加入到这个队列中),monitorexit的时候,就会唤醒队列中的线程。

11)wait、notify、notifyall
        sychronized(lock){
            lock.notify();  // 如果没有获得锁,无法唤醒别人
        }

        不加sychronized会有2个问题:
            会抛出异常错误。
            为了感知要释放哪个锁。

        wait的2个作用: 实现线程的阻塞 + 释放当前的同步锁
            毕竟自己wait不释放,那么其它线程无法获取到锁,也无法通知它被唤醒。

        notify/notifyall: 唤醒1个/唤醒所有


12)偏向锁,就是重入锁

13)轻量级锁:AQS有实现

14)重量级锁:AQS也有实现

15)AQS是一种同步队列

16)wait:释放锁资源和cpu资源。
    sleep: 只是变为waiting状态。同时释放CPU资源。

17)场景--》需求--》解决方案--》应用--》原理
场景:多线程场景
需求:多线程并行产生的线程安全性
解决方案: 加锁(synchronized)
应用: synchronized的集中用法。 实例锁、静态方法锁、代码块
原理: 偏向锁(前提是:大部分情况下只有一个线程去访问锁对象)--》轻量级锁(CAS 自选锁)--》重量级锁(mutex 互斥锁)

18)volatile: 可见性、原子性、有序性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值