在java中使用synchronized进行同步,锁的类型有类锁与对象锁之分。
一、对象锁
当多个线程操作同一个实例的时候才产生作用。
1、修饰代码块
使用this:属于对象锁
public void do() {
synchronized (this) { // this:属于对象锁 与public synchronized void doVoid() { } 同步
System.out.println("is base");
}
2、修饰方法
这种直接修饰在方法是咱个情况?其实和修饰代码块类似,只不过此时默认使用的是this,也就是当前对象的锁。这样写起代码来倒也比较简单明确。与第一点修饰代码块的区别主要还是控制粒度的区别。
public synchronized void doVoid() { } //对象锁 与synchronized (this){} 同步
多线程同时执行上述两种方法是需要同步的,获取对象锁才能执行。
二、类锁
当多个线程操作不同的实例,但是这些实例同属于一个类时候产生作用。
1、修饰静态方法
private static synchronized void method1(){ //类锁
//与synchronized (BaseClass.class){} 同步
}
静态方法难道有啥不一样吗?确实是不一样的,此时获取的锁已经不是this了,而this对象指向的class,也就是类锁。因为Java中的类信息会加载到方法常量区,全局是唯一的。这其实就提供了一种全局的锁。
2、使用xxx.class
public static void doStaticVoid() {
synchronized (BaseClass.class) { //类锁,此方法执行,则与private static synchronized void method1()方法同步
//这种情况其实和修改静态方法时比较类似,只不过还是一个道理这种方式可以提供更灵活的控制粒度。
}
}
}
多线程同时执行上述两种方法是需要同步的,获取类锁才能执行。
三、总结
何时产生同步?
假如我们有两个 Student类的实例stu1、stu2。
Student类中的方法如下:
class Student{
//对象锁
public void fun1() {
synchronized (this) {
.....
}
//对象锁
public synchronized void fun2() {
.....
}
//类锁
public void fun3() {
synchronized (Student.class) {
.....
}
//类锁
public synchronized void fun4() {
.....
}
}
1、 线程A操作stu1中的对象锁方法即fun1或者fun2,线程B操作stu2中的对象锁方法即fun1或者fun2,则A、B线程不会产生同步,一个获取stu1的对象锁,一个获取stu2的对象锁,何来同步呢?
若A、B两线程同时操作stu1中的对象锁方法即fun1或者fun2,则会产生同步。
2、 线程A操作stu1中的类锁方法即fun3或者fun4,线程B操作stu2中的类锁方法即fun3或者fun4,则A、B线程产生同步,两线程获取的是一个锁,即 Student类锁。