细论Synchronize的使用区别
Synchronize的作用
在并发编程中实现共享数据的同步。
Synchronize使用形式
Synchronize的使用方式大体分为两种:Synchronize同步方法 以及 Synchronize块。其本质都是对目标对象(或类)的锁定,让该方法变为原子操作。
Synchronize同步方法
Synchronize同步方法的使用上大致也分为两种情况:修饰普通方法,与修饰静态方法。
Synchronize修饰普通方法
先谈谈修饰普通方法,当我们给一个普通方法加上Synchronize修饰词。此时,该方法即能实现同步。我们用不同的线程去跑这个方法时,同一时间,只能有一个线程进入该方法。保证了共享资源的安全性。
public synchronized void Something_A()
但是这里有几个注意点:
- 在用多线程去跑该同步方法时,须注意改同步方法是否是来自于同一个实例对象。因为同步方法是属于对象的,不同的对象的同步方法并不是同一个同步方法,也就意味着线程获取的锁,并不是同一把锁。以至于线程并不能实现同步。
- 同一个类中如果有多个Synchronize修饰的方法,那么当一个线程获取了一个方法的锁后,其他线程并不能进入该类中任意Synchronize修饰的方法(除静态方法)。这也说明了Synchronize锁的对象,在同步方法与静态方法时不同的。(下面一段我会讲到Synchronize修饰普通方法与修饰静态方法的不同。)
Synchronize修饰静态方法
public synchronized static void Something_B()
与Synchronize修饰普通方法一样。修饰静态方法也是让多线程实现同步。当有线程获取锁后,其他线程便不能进入Synchronize修饰的静态方法。
那么其与Synchronize修饰的普通方法有什么不同呢?其实很简单,Synchronize修饰方法其实是对类或者对象加锁。当Synchronize修饰普通方法时,是对当前对象(this)加锁,而当其修饰静态方法时,是对类进行加锁。这一点很重要,也是对后面理解Synchronize块有帮助的。
所以针对上文的注意点,Synchronize修饰静态方法也有一些注意点:
- 因为其修饰的是静态方法,而静态方法是属于类本身的。而无论实例化多少个对象,该类依旧只有一个。所以,如果线程跑的不是一个实例化对象的静态同步方法,也会有同步的效果。因为Synchronize是对该类上锁。
- 而为什么前文提到的某一线程获取Synchronize修饰的普通方法后,其他依旧可以进入Synchronize修饰的静态方法,原因不言而喻。前者获取的是实例化对象的锁,而后者获取的是类的锁。
对于Synchronize修饰同步方法,就先讲到这里。
其实在在使用时,我们会出现一种情况。例如当一条线程进入Synchronize后,对其中的属性A进行长时间的操作。而另一条线程在此期间想对属性B进行短时间操作,但因为Synchronize修饰的原因,只能排队等待。
这并不符合我们的逻辑,因为对于属性A的更改与对属性B的更改并不需要同步,但我们为了防止其他线程进入更改该线程的进入本方法,所以又不得不使用Synchronize。所以这种时候我们便可以使用Synchronize块。
Synchronize块
在了解了Synchronize修饰方法后,我们其实很容易再理解Synchronize块的应用。其原理就是对我需要锁定的对象或类上锁。而这里我们也可以再细化出三种情况:
Synchronize修饰非this对象
此时Synchronize锁定的便只是指定的该对象。例如上面所说的例子中,我们便可以使用如下方法提高同步的性能:
public void Something_A()
{
synchronized (A)
{
//此处为对A的操作。
}
}
public void Something_B()
{
synchronized (B)
{
//此处为对B的操作。
}
}
因为两个Synchronize所锁定的不是同一个对象,所以在某一线程进入Something_A()的Synchronize块时,其他线程依旧可以进入Something_B()中的Synchronize块。
Synchronize修饰this对象
该原理与Synchronize块修饰普通方法相同,是对本对象的锁定。故其性质也与之前的Synchronize修饰普通方法相同。
synchronized (this)
{
}
Synchronize修饰class
该原理与Synchronize块修饰静态方法相同,是对类的锁定。故其性质也与之前的Synchronize修饰静态方法相同。
synchronized (this.class)
{
}
//当然也可以延伸出下面的形式
synchronized (Object.class) // object为任意对象
{
}
总结
- Synchronize的作用是针对并发编程,实现同步。
- Synchronize的本质是对对象或类上锁,而不是对于某一方法上锁。
- 在判断线程是否同步时,我们即可根据上文的方法观察线程是否在争抢同一把锁。
- 在使用Synchronize时,我们应注意使用volatile关键字实现数据的同步。