zoukankan      html  css  js  c++  java
  • synchronized关键字

      synchronized关键字用于实现线程间同步,经过编译之后,会在同步块前后分别形成monitorenter和monitorexit这两个字节码指令。这两个字节码都需要一个reference类型的参数来指明要锁定和解锁的对象。如果synchronized明确指定了对象参数,就使用这个对象的reference;如果没有明确指定,就根据synchronized修饰的是实例方法还是类方法,去取对应的对象实例或Class对象来作为锁对象。

      在执行monitorenter指令时,首先要尝试获取对象的锁,如果这个对象没被锁定,或者当前线程已经拥有了这个对象的锁,就把锁的计数器加1;在执行monitorexit指令时会将计数器减1,当计数器为0时,锁就被释放。如果获取对象锁失败,就处于阻塞状态,直到被其他线程释放。

    用法:

      1. 指定加锁对象:给某个对象加锁,进入同步代码前要获取这个对象的锁。注意:必须保证锁的是同一个对象实例,若两个线程运行时,某方法中锁的对象不是同一个,同步不起作用。

    Test instance = new Test();
    public void run(){
        synchronized(instance){
        //todo
        }  
    } 

      2. 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。注意:必须保证操作的是同一个对象,若两个线程分别new了一个相同类的对象,同步不起作用。

    public synchronized void run(){
        //todo
    }

      3. 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。当两个线程分别new了一个相同类的对象,同步也起作用,因为锁的是这个 类。

    public static synchronized void run(){
        //todo
    }
    

    常用集合:

    ArrayList线程不安全,Vector线程安全

    HashMap线程不安全,ConcurrentHashMap线程安全

    StringBuilder线程不安全,StringBuffer线程安全

    错误对Integer加锁:

    public Integer i = 0;
    synchronized(i){
       i++;  
    }
    

    例如上面代码,对i进行了加锁。但是这违背了用法1的规范,对指定对象加锁必须是同一个对象,当执行i++后,实际上是调用Integer.valueOf()新建了一个对象赋值给i(i = Integer.valueOf(i.intValue()+1)),此时i是一个新对象,所以每次加锁都加在了不同对象上。

      

  • 相关阅读:
    linux(ubuntu) 系统修改/etc/fstab文件后无法进入系统的解决方法-摘录
    linux实现实时同步服务
    linux利用网易邮箱发送邮件
    企业数据库备份方案——mysqldump完全备份+binlog增量备份
    Nginx下隐藏index.php
    linux日志详解-摘录
    expect免交互用法
    删除超过多少天的日志文件或者备份文件
    Python_结合Re正则模块爬虫
    Jmeter性能分析
  • 原文地址:https://www.cnblogs.com/wwzyy/p/10096553.html
Copyright © 2011-2022 走看看