zoukankan      html  css  js  c++  java
  • synchronized

      1、synchronized的几种基本用法:

      https://gitee.com/play-happy/base-project/tree/developer/src/main/java/org/burning/sport/javase/thread/synchronizeds

    public class SynchronizedTest1 {
    
        private Object lock = new Object();
        /**
         * ①对于普通统发方法,锁是当前实例对象
         */
        public synchronized void f() {
        }
        /**
         * ②对于静态同步方法,锁是当前类的Class对象
         */
        public synchronized static void g() {
        }
        /**
         * ③对于普通方法快,锁是synchronized括号里配置的对象
         */
        public void p() {
            synchronized (lock) {
            }
        }
        public void q() {
            synchronized (this) {
            }
        }
    public void k() {
      synchronized(SynchronizedTest1.class) {
    }
    } }

      ps: synchronized方法(比如①)和synchronized代码块(比如③)的性能相比较,①比②性能要低,所以尽量用synchronized代码块

      2、加锁的错误用法

    /**
     * 加锁的错误示例
     * 示例中两个加锁的方法,它们的锁对象不是同一个,对于方法f()的锁对象是this,也就是SynchronizedTest2
     * 对于方法g()的锁对象是Object,所以这两个方法的同步是互相独立的
     */
    public class SynchronizedTest2 {
    
        private Object lock = new Object();
    
        public synchronized void f() {
            for(int i = 0; i < 5; i++) {
                System.out.println("f(" + i + ")");
                Thread.yield();
            }
        }
    
        public void g() {
            synchronized (lock) {
                for(int i = 0; i < 5; i++) {
                    System.out.println("g(" + i + ")");
                    Thread.yield();
                }
            }
        }
    
        public static void main(String[] args) {
            final SynchronizedTest2 test2 = new SynchronizedTest2();
            new Thread() {
                @Override
                public void run() {
                    test2.f();
                }
            }.start();
            test2.g();
        }
    }

       3、锁的升级与对比

      JavaSE6.0 锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。这几个状态会锁着锁竞争而升级。

    锁可以升级而不能降级

      3.1 偏向锁:

        为了让线程获得锁的代价更低而引入了偏向锁。当一个线程访问同步块并获取锁时,会在对象头帧栈中的锁记录里存储偏向的线程ID,以后该线程在进入和退出同步块时不需要CAS操作来加锁和解锁,只需

      要简单的测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功表示线程已经获得了锁。

      3.2 轻量级锁:

        线程在执行同步块之前,JVM会先在当前线程的帧栈中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方成为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark

      Word 替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

       4、synchronized的可重入性(对比重入锁:ReentrantLock)

          什么叫做锁的重入性? 当一个线程再次请求自己持有对象锁的临界资源时,这种情况属于重入锁。在java中synchronized是基于原子性的内部锁机制,是可重入的,因此在

      一个线程调用synchronized方法的

        同时在其方法体内部调用该对象另一个synchronized方法,也就是说一个线程得到一个对象锁后再次请求该对象锁,是允许的,这就是synchronized的可重入性。

      synchronized是隐式的支持重进入。

    Demo1:

    public class SynchronizedTest3 implements Runnable{
        int a = 0;
        int b = 0;
    
        public static void main(String[] args) throws InterruptedException {
            SynchronizedTest3 test = new SynchronizedTest3();
            Thread t1 = new Thread(test);
            Thread t2 = new Thread(test);
            //启动两个线程跑
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println(test.a);
            System.out.println(test.b);
        }
        //这个的锁对象是当前实例对象
        public synchronized void increase() {
            b++;
        }
    
        @Override
        public void run() {
            for(int i = 0; i < 1000; i++) {
                //这个的锁对象也是当前实例对象
                synchronized (this) {
                    a++;
                    increase();
                }
    
            }
        }
    }
    /*
      output:
      2000
      2000
     */

     Demo2:

    public class Widget {
        public synchronized void doSomething() {
            ......
        }
    }
    
    public class LoggingWidget extends Widget {
        public synchronized void doSomething() {
            //业务操作
            super.doSomething();
        }
    }

      5、线程的中断与synchroinzed  参考:https://www.cnblogs.com/happyflyingpig/p/9716055.html

       事实上线程的中断操作对于正在等待获取的锁对象的synchronized方法或者代码块并不起作用,也就是对于synchronized来说,如果一个线程在等待锁,那么结果只有两种,要么它获得这把锁继续执行,要么它

       就保存等待,即使调用中断线程的方法,也不会生效。

        6、等待唤醒机制与synchroinzed

        所谓等待唤醒机制本篇主要指的是notify/notifyAll和wait方法,在使用这3个方法时,必须处于synchronized代码块或者synchronized方法中,否则就会抛出IllegalMonitorStateException异常,

        这是因为调用这几个方法前必须拿到当前对象的监视器monitor对象,也就是说notify/notifyAll和wait方法依赖于monitor对象,我们知道monitor 存在于对象头的Mark Word 中(存储monitor引用指针),

        而synchronized关键字可以获取 monitor ,这也就是为什么notify/notifyAll和wait方法必须在synchronized代码块或者synchronized方法调用的原因。

    synchronized (obj) {
           obj.wait();
           obj.notify();
           obj.notifyAll();         
     }

       需要特别理解的一点是,与sleep方法不同的是wait方法调用完成后,线程将被暂停,但wait方法将会释放当前持有的监视器锁(monitor),直到有线程

      调用notify/notifyAll方法后方能继续执行,而sleep方法只让线程休眠并不释放锁。同时notify/notifyAll方法调用后,并不会马上释放监视器锁,而是在

      相应的synchronized(){}/synchronized方法执行结束后才自动释放锁。

    参考:

      【1】《Think in Java》第四版

           【2】《Java核心技术》卷Ⅰ 

      【3】《Java并发编程的艺术》,方腾飞

      【4】《Java高并发程序设计》,葛一鸣

      【5】《Java并发编程实战》,童云兰

      【6】博客,https://blog.csdn.net/javazejian/article/details/72828483

      【7】博客,http://www.cnblogs.com/skywang12345/p/3479202.html

  • 相关阅读:
    Navicat 12 的安装和破解
    Intellij ide 2017.2新建javaweb项目,并且部署
    javaSE 打印九九乘法表
    jquery.validate remote 和 自定义验证方法
    MySQL命令行导出数据库
    从cookie中取值$.cookie()
    23个MySQL常用查询语句
    正则表达式限制文本框只能输入数字,小数点,英文字母,汉字
    jquery从零开始学----选择器
    文件上传利器SWFUpload使用指南
  • 原文地址:https://www.cnblogs.com/happyflyingpig/p/9615259.html
Copyright © 2011-2022 走看看