}
}
}
如:为代码块加锁,锁对象为我们创建的任意一个对象。不要使用非final的成员变量作为同步锁对象,因为非final成员变量可以被重新赋值,导致不同的线程使用不同的对象作为锁,达不到同步锁定的效果。
public class DemoClass{
//注意这里的关键字final非常重要,看说明
private final Object lock = new Object();
public void demoMethod(){
synchronized (lock){
//同步代码块
}
}
}
[]( )2\. 类级别的同步锁
--------------------------------------------------------------------
类级别的锁可以防止多个线程在运行时进入该类所有实例化对象的 "synchronized块中。也就是说如果运行时有100个`DemoClass`的实例,那么每次只有一个线程能够在任何一个实例中执行`demoMethod()`,所有其他实例的所有其他线程都被锁定。
为了保障静态数据线程安全,应该使用类级别的锁定。我们知道static关键字将方法的数据关联到类的级别上,所以在静态方法上使用锁。
静态方法加锁,对该类所有的实例化对象生效
public class DemoClass{
//静态方法加锁,对该类所有的实例化对象生效
public synchronized static void demoMethod(){
}
}
获取 .class类的引用,类级别的锁
public class DemoClass{
public void demoMethod(){
//获取 .class类的引用,类级别的锁,对该类所有的实例化对象生效
synchronized (DemoClass.class){
//同步代码块
}
}
}
使用静态对象的锁,类级别的锁
public class DemoClass{
//静态对象,类级别,注意这里的关键字final非常重要
private final static Object lock = new Object();
public void demoMethod(){
//使用静态对象的锁,类级别锁,对该类所有的实例化对象生效
synchronized (lock){
//同步代码块
}
}
}
[]( )3\. 总结
---------------------------------------------------------------
1. Java中的同步机制保证了两个或多个线程无法同时执行一个需要相同同步锁的方法。
2. "synchronized "关键字只能用于方法和代码块。这些方法或代码块可以是_静态_或_非静态_的。
3. 当一个线程进入`synchronized`方法或代码块时,它就会获得一个锁,当它离开同步方法或代码块时,它就会释放这个锁。如果线程执行过程出现任何错误或异常,锁也会被释放。
4. 使用"synchronized "关键字持有的锁在本质上是可重入的,这意味着如果一个同步方法调用另一个**使用相同锁**的同步方法,那么持有锁的当前线程可以进入该方法而无需再次获得锁。
5. 如果同步块中使用的对象为空,Java synchronized 将抛出NullPointerException
6. 使用`synchronized`同步方法会给你的应用程序带来性能成本。因此,尽量在绝对需要的情况下才使用同步。另外优先考虑使用同步代码块,并且只同步代码的关键部分。
7. 静态同步方法和非静态同步方法有可能同时或并发运行,因为它们使用的是不同的锁。
8. 根据Java语言规范,你不能在构造函数中使用`synchronized`关键字。这是不合法的,会导致编译错误。
9. 不要使用非final的成员变量作为同步锁对象,因为非final成员变量可以被重新赋值,导致不同的线程使用不同的对象作为锁,达不到同步锁定的效果。
10. 不要使用字符串字面量作为锁对象,如:`String a = "1";`,因为它们可能会被应用程序中的其他地方引用,并可能导致死锁。用`new`关键字创建的字符串对象可以安全使用。