对象锁与类锁

public class Person {

    private String name;
    
    private static final String TAG = Person.class.getSimpleName();

    public Person(String name) {
        this.name = name;
    }

    // Synchronized修饰一个方法
    public synchronized void say(){
        for(int i = 0; i < 10; i++){
            try {
                Log.d(TAG, name + " say -> " + i)
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    // Synchronized修饰一个代码块
    // 如果像这样代码块是函数内的全部代码,那同步效果与上面修饰方法是一样的
    public void say(){
        synchronized(this) {
            for(int i = 0; i < 10; i++){
                try {
                    Log.d(TAG, name + " say -> " + i)
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
       
    }

    public void talk(){
        for(int i=0;i<3;i++){
            try {
                Log.d(TAG, name + " talk -> " + i)
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

这个属于对象锁,synchronized锁定的是对象(实例?),这时会有两把锁分别锁定 对象1对象2,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行。

Person person1 = new Person();
Person person2 = new Person();

如果两个线程同时分别对两个对象进行操作,两个对象的函数 say 或者 talk 是不会锁定的,互补干扰。

但是如果这么写

public void say(){
        synchronized(Person.class) {
            for(int i = 0; i < 10; i++){
                try {
                    Log.d(TAG, name + " say -> " + i)
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
       
    }

这样的话,锁定的范围就扩大到 类了,属于类锁,不再局限为对象。

所有这个类的实例,都会存在同步的效果

Tips

当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的对象来充当锁:

private byte[] lock = new byte[0];  // 特殊的常量,为什么用byte[]
   public void method()
   {
      synchronized(lock) {
         // Todo 同步代码块
      }
   }

零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。