Java中的锁—类锁、对象锁

规律总结

  • 并发。首先应该意识到只有在多线程(并发)的情况下才会有锁的竞争、获取的问题,单线程根本是不需要考虑锁的。
  • 同步一个非同步的操作,在任何情况下都是可以被无阻塞执行的,无论对象或者是否处于锁状态。例如:对象A被锁住,但是这时对象A仍然可以被调用进行任何非同步操作。
  • synchronizedsynchronized修饰的代码块必须执行完(退出)才会释放锁。 synchronized修饰的代码块肯定要获得类锁或者对象锁。代码块执行完才会释放它持有的锁,比如:synchronized修饰方法method()时,直到method执行完退出(return)才会释放锁,return之后是肯定会释放锁的。(例外:wait()方法会提前释放锁,notify()方法不会提前释放锁)
  • 类锁每一个类只有一个锁,同步静态方法会持有类锁。但是static对象、final对象是获取对象锁,不是类锁。public static synchronized void method() 这种同步、静态方法在运行的时候会直接占有类锁。并发状态下,此时任何想要获取类锁的操作都会失败。
  • 对象锁。每一个对象都有一把锁。这里的可以是类的实例,也可以是静态对象、final对象。应该注意的是:当用synchronized 修饰一个类的静态对象的时候,获取的是该静态对象锁,而不是类锁。

类锁

获取类锁的两种操作

  • 同步静态方法。就是上面说的public static synchronized void method()。同步静态方法中synchronized(this)也会获取类锁,因为这里的this就是class对象。
  • 直接用synchronized修饰类名。例如synchronized (LockClass.class) 代码示例:
    public class LockClass{    
        /**
         * 这个方法执行的时候会获取类锁
         */
        public static synchronized void method() {
    
        }
    
        public void testMethod() {
            synchronized (LockClass.class) {    //获取类锁
    
            }
        }
    }
    

关于类锁的说明

  • 当类锁被占用的时候,其他线程中上述两种获取的类锁的操作都会被阻塞(blocked)。
  • 因为类锁会锁住当前类的所有同步静态方法,应该减少类锁的使用,减小synchronized修饰的代码块的范围,代码块越小,释放锁的速度越快。缩小锁范围的示例:
    public class LockClass {
        static Object object = new Object();
        /**
         * 不推荐这种直接用synchronized修饰方法
         */
        public static synchronized void Bad() {
    
        }
        //更好的一种方式
        public static void Better() {
            // TODO: 2017/12/10  不需要锁的操作在这执行···
    
            /*
            用object对象进行同步操作,这里获取的object对象锁,缩小了同步代码块的范围
            如果用this或者类名,会获取类锁,不如获取object对象锁的方式
             */
            synchronized (object) {
    
            }
    
            // TODO: 2017/12/10 不需要锁的操作在这执行···
        }
    }

  • 在Android开发中,由于类锁范围很大,比对象锁更容易造成ANR,所以应该考虑上面减小锁范围的方式。

对象锁

获取对象锁

  • public synchronized void method()会获取调用者的对象锁。
  • synchronized(object)会获取object对象的对象锁。
  • 同步非静态方法中的synchronized(this)会获取调用者的对象锁。

关于对象锁的说明

  • 注意不同实例对象的锁互不影响。当对象A调用同步非静态方法method时,此时对象A的锁是被获取的,对象A不能进行其他的同步操作,但是此时对象B也是可以调用方法method。
  • static对象,final对象,也是有对象锁的,并不会获取类锁,对类锁没有影响。
  • 一个非同步的操作,在任何情况下都是可以被无阻塞执行的,无论对象是否处于锁状态。
  • 应该考虑用synchronized(this)的方式减小锁的代码块的范围。

猜你喜欢

转载自blog.csdn.net/followyouself/article/details/78747432