java synchronized的深刻认识

本文详细解析了Java中synchronized关键字的使用方法及其锁机制。包括synchronized在实例方法、静态方法及代码块中的应用,以及锁对象的概念,帮助读者理解如何正确地使用synchronized实现线程同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

synchronized分两种场景:

(1)普通方法前加synchronized

synchronized public void test(){...}

      该操作等价于在方法体前后包装一个synchronized(this),或者说给当前类所在的对象加上了锁标记。与它互斥的情况通常有以下3种(也就是相互之间是串行的):

  • 在该类的所有非静态方法中发生synchronized(this)
  • 在该类的所有非静态方法前面加上了synchronized关键字
  • 在其他类中得到该对象的引用,并对该对象进行synchronized操作
(2)静态 方法前面加synchronized
synchronized public static void test(){...}
       这个锁操作等价于锁住了当前类的class对象,比如这个类叫作A,那么相当于执行了 synchronized(A.class)操作。与它互斥的场景就十分明显了:
  • 代码中任意一个地方发生了synchronized(A.class)。
  • 在该类的所有静态方法前面增加了synchronized关键字
synchronized主要就是这两种方式,其余的方式都是在这个基础上衍生出来的,如代码块加锁
synchronized(object)
{
	//代码内容
}

###########详解##############


JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。假如再细的分类,synchronized可作用于instance变量、object reference(对象引用,例如this)、static函数和class literals(类名称字面常量)身上。下面讨论synchronized用到不同地方对代码产生的影响:

假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都能够调用他们。
1.把synchronized当作函数修饰符时,示例代码如下:
public synchronized void method(){
    //….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?他锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,他们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却能够任意调用这个被加了synchronized关键字的方法。上边的示例代码等同于如下代码:
public void method(){
    synchronized (this) // (1){
      //…..
    }
}
(1)处的this指的是什么呢?他指的就是调用这个方法的对象,如P1。可见,同步方法实质是将synchronized作用于Object Reference。那个拿到了P1对象锁的线程,才能够调用P1的同步方法,而对P2而言,P1这个锁和他毫不相干,程式也可能在这种情形下摆脱同步机制的控制,造成数据混乱。
2.同步块,示例代码如下:
public void method(SomeObject so) {
    synchronized(so){
      //…..
    }
}
这时,锁就是so这个对象,谁拿到这个锁谁就能够运行他所控制的那段代码。当有一个明确的对象作为锁时,就能够这样写程式,但当没有明确的对象作为锁,只是想让一段代码同步时,能够创建一个特别的instance变量(它得是个对象)来充当锁:
class Foo implements Runnable{
    private byte[] lock = new byte[0]; // 特别的instance变量
    public void method(){
      synchronized(lock) { //… }
    }
    //…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济。查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
3.将synchronized作用于static 函数,示例代码如下:
Class Foo{
    public synchronized static void method1() // 同步的static 函数{
    //….
}
public void method2(){
    synchronized(Foo.class) // class literal(类名称字面常量){
    }
}

代码中的method2()方法是把class literal作为锁的情况,他和同步的static函数产生的效果是相同的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class类,而不再是由这个Class产生的某个具体对象了)。


转载自:http://www.strutshome.com/index.php/archives/495

详细参考:http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html

http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html

一句话概括:两种锁对象;一种是实例对象,一种是class对象,分别对应动态和静态


总结:

需要注意的是同步加锁的是对象而非代码,如果在一个类中有一个同步方法,该方法是可以被两个不同的线程同时执行的。只要每一个线程自己创建一个该类的实例即可。
synchronized关键字锁的是对象而不是代码块,如果需要实现真正的同步,必须同步一个全局对象或者对类进行同步。通过对当前类进行加锁,达到了同步的效果,但是基于线程同步的一般原理是应该尽量减少同步的粒度以达到更高的性能。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值