每一个对象都有一把独占锁。独占锁只限制线程对它的同步方法的访问,对非同步方法,独占锁没有意义。
synchronized关键字可以作为函数的修饰符,也可以作为函数内的语句,也就是平时说的同步方法和同步代码块。如果再细分的话,synchronized可以作用域instance变量、对象引用、static函数和类上。
不过无论synchronized关键字加载方法上还是对象上,它取得的锁都是对象锁。而不是把一段代码或者函数当做锁。所以说,尽管我们对方法进行了同步,该同步方法还是有可能被其他线程的对象访问的。
作用域
1、在某个对象实例内
比如代码块儿、方法上的同步,可以防止多个线程同时访问这个对象(注意:是这一个对象。该类的其他对象的同步方法对应另外一个对象锁)的同步方法。这时,不同对象实例的同步方法,是不互相干扰的。也就是说,其他线程依然可以访问相同类的另一个对象的同步方法。
如果一个对象里可以有任意多个同步方法。任意时间里只能有一个线程访问这个对象的这些同步方法。
例如,现成T1在访问同步方法Method1,此时还有一个同步方法Method2此时无人访问,但是由于已经有一个线程正在访问这个对象的同步方法Method1,所以试图访问Method2的线程将被阻塞。直到T1对M1的访问结束。
可见同步方法有在一个同步方法运行期内保证只有一个线程能够进入。一旦方法结束,里面的线程就会失去对该对象的独占权。 synchronized语句块,可以指定要获得哪个对象的独占权,一旦获得,在语块执行过程中,线程会始终掌握该对象的独占权。此时,它可以连续访问多个该对象的同步方法。在整个过程中,独占权都牢牢掌握在该线程手中,其它线程没有任何机会。而如果没有同步语句块,则如果连续访问某个对象的同步方法,则在前一个方法返回,到下一个方法调用的间隙内,其他线程有机会抢先获得该对象的独占权。
PS:synchronized关键可以修饰函数、函数内语句。无论它加上方法还是对象上,它取得的锁都是对象,而不是把一段代码或是函数当作锁。
2、某个类的范围
比如在静态方法上加上同步关键字,由于静态方法是类级别的,所以它可以多累的所有对象实例都起作用。
synchronized方法控制对类成员变量的访问:每个类实例一把锁,每个同步方法都必须获得调用该方法的类实例的锁,才能执行,否则该线程会进入阻塞状态,一旦执行,就独占该锁,知道其释放锁为止。
这种机制确保了同一时刻对应一个类实例,有效避免类成员变量访问冲突的问题。属于以牺牲效率确保安全的策略。
PS:Java中,不仅类的每个对象都队赢一把独占锁,每一个类也对应了一把锁。我们可以将类的静态成员声明为synchronized,来控制器类的静态成员变量的访问。
总结一下:
通过上面的论述,我们可以得出:synchronized关键字的同步方法,本质上是 作用于对象的引用。哪一个线程拿了对象锁A,就能够调用该对象的同步方法;而对象锁B,与A锁毫不相干,程序可以通过对象锁B任意访问同步方法。
3、同步代码块
同步代码块也值得一提。代码块中的同步,表示对这个区块的资源实行呼哧访问,它的作用域也是当前对象。这时锁就是对象,谁拿到了这个锁,就可以运行它锁控制的那段代码。
PS:synchronized关键字是不能继承的,集成类需要你显示指定它的某个方法为同步方法。