美文网首页
Java Synchronized

Java Synchronized

作者: yikemi | 来源:发表于2022-02-24 16:32 被阅读0次

    一、为什么需要锁

    存在共享数据。
    当出现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转换为直观可控的对象行为。

    相关文章

      网友评论

          本文标题:Java Synchronized

          本文链接:https://www.haomeiwen.com/subject/eedzlrtx.html