此文章为在学习过程中,对Synchronized的理解和总结;文中可能有些不严谨或认识错误,望读者指出!
java中使用synchronized关键字来标记代码块,使被标记代码同一时间只能被一个线程执行。使用互斥锁对象来控制进入的线程。如同厕所的门上的有人/无人的一样,有人在门被锁上,其他人无非法进入,没人在门可以之间打开进入。
在类中可以对方法,代码块使用Synchronized关键字,默认锁对象是this,即访问者本身。如下代码中,swap()和swap2()中都使用该关键字进行标记,且互斥锁对象都为this,则swap()方法在执行时,swap()和swap2()方法都将会被锁住。
class MyClass
{
private String name1 = "阿莉";
private String name2 = "莉娜";
public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
public void swap2()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
当Synchronized关键字写在方法声明中且不指定互斥锁对象时,等同于在方法中使用关键字标记方法中的所有代码,且默认锁对象为this,即对于不同线程中使用的同一实例同步,比如线程1中使用MyClass的对象1执行swap方法,线程2中也是使用对象1进行访问swap方法,则需要让两个线程里的对象1保持一致(对象的数据,状态等)。个人理解,通常应该设置为代码块中执行后可能会发生变化的的对象,例如代码块执行后会改变自身对象的成员变量并进行一些计算,那么需要将自身对象(this)同步。
如果方法为静态方法且不指定互斥锁对象时,等同于在方法中使用关键字标记方法中的所有代码,且默认锁对象为当前类名.class对象。
class MyClass
{
private static String name1 = "阿莉";
private static String name2 = "莉娜";
public synchronized void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}
public static synchronized void swap2()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
等同于
class MyClass
{
private static String name1 = "阿莉";
private static String name2 = "莉娜";
public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
public static void swap2()
{
synchronized (MyClass.class)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
可以看出,由于静态方法可以直接用类名.方法名调用,不需类的实例对象,因此不能使用实例对象作为互斥锁对象,而应使用类的字节码对象,如Myclass.class,String.class等等;