(49)静态同步函数的锁是Class对象,例子:懒汉式--在多线程中存在问题--同步解决
一、如果同步函数被静态修饰后,使用的锁是什么呢?
通过验证,发现使用的不是this.因为静态方法中也不可以定义this
静态进内存,内存中没有本类对象,但是一定个该类对应的字节码文件对象。
类名.class 该对象的类型为Class.
静态的同步方法,使用的锁是该方法所在类的字节码文件兑现,类名.class
二、懒汉式—-在多线程中存在安全问题
class Single
{
private static Single s=null;
private Single(){}
public static Single getInstance(){
if(s==null)
s=new Single();
return s;
}
}
这个静态方法被run调用后,存在安全问题原因:
s是个共享数据,当一个线程执行到if(s==null)时,判为真时,cpu执行其他的程序去了,比如此时另一个线程,此时执行if(s==null),因为刚才的线程并没有创建对象,所以判断为真,这样就会创建两个对象,存在安全问题
将此函数改为同步函数,就可以解决这个问题。
class Single
{
private static Single s=null;
private Single(){}
public static synchronized Single getInstance(){
if(s==null)
s=new Single();
return s;
}
}
但是这样会使得多线程运行效率低,原因是加锁多个判断条件。
class Single
{
private static Single s=null;
private Single(){}
public static Single getInstance(){
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s=new Single();
}
}
return s;
}
}
为什么在synchronized中也要写个if(s==null)呢?
举个栗子说明:
第一个线程在外层if判断成功后,进入同步块,判断内部的if,成立,此次CPU被剥夺,比如执行到第二个线程,同样判断外层的if,因为上同步块上着锁,进不了,隔一段时间,第一个线程得到cpu,继续执行,创建了对象,开锁。然后隔一段时间,第二个线程继续执行,进入共享区,然后if(s==null)判断失败,开锁,这就防止了创建对个对象。因为只有一个对象,所以以后的外层if (s==null)
都判断失败,因为已经有对象了,这样就摆脱了在多线程中使用同步方法、,每次都判断是否有锁,运行效率有所提高。