synchronized的用法
三种用法:
- 修饰实例方法
- 修饰静态方法
- 修饰代码块
synchronized的作用:
- 原子性:synchronized保证语句块内操作是原子的
- 可见性:synchronized保证可见性(通过“在执行unlock之前,必须先把此变量同步回主内存”实现)
- 有序性:synchronized保证有序性(通过“一个变量在同一时刻只允许一条线程对其进行lock操作”)
一、3种用法
synchronized是Java中的关键字,是一种同步锁。
- 修饰一个普通方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
- 修饰一个静态方法:其作用的范围是整个方法,作用的对象是这个类的所有对象
- 修饰一个代码块:被修饰的代码块称为同步语句块,其作用范围是大括号{}括起来的代码块,作用的对象是调用这个代码块的对象;
synchronized关键字不能继承。
修饰一个类和修饰一个静态方法,作用的对象都是这个类的所有对象。
修饰一个普通方法和一个代码块,作用的对象是调用这个方法或者代码块的对象。
(1)修饰一个普通方法
直接在方法的返回类型之前加synchronized关键字修饰
作用的对象是调用这个方法的对象(每个对象一把锁)
// 作用的对象是调用这个方法的对象;
public synchronized void method(){
//TODO
}
public void method(){
synchronized(this) {
// todo
}
写法一修饰的是一个方法,写法二修饰的是一个代码块,但写法一与写法二是等价的,都是锁定了整个方法时的内容。
接口方法不能使用synchronized关键字
构造方法不能使用关键字,但可以使用synchronized代码块进行同步
如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。
//在子类方法中加上synchronized关键字
class Parent {
public synchronized void method() { }
}
class Child extends Parent {
public synchronized void method() { }
}
----
//在子类方法中调用父类的同步方法
class Parent {
public synchronized void method() { }
}
class Child extends Parent {
public void method() { super.method(); }
}
(2)修饰一个静态方法
静态方法时属于类而不是属于对象的,所以synchronized修饰的静态方法锁住的是这个类的所有对象。这个锁是类锁(与前面的那个不同,前面的那个是对象锁),所有对象共用一把锁。
//其作用的范围是整个方法,作用的对象是这个类的所有对象;
public synchronized static void func2(){
//TODO
}
(3)修饰一个代码块
一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞
public class ClassB {
//类的实例对象: 同步代码块,锁住的是该类的实例对象
//其作用范围是大括号{}括起来的代码块,作用的对象是调用这个代码块的对象
synchronized(this) {
//TODO
}
//类对象: 同步代码块,锁住的是该类的类对象(该类的所有实例),所有实例对象共用一把类锁
synchronized(ClassB.class) {
//TODO
}
//任意实例对象Object: 同步代码块,锁住的是配置的实例对象
//String对象作为锁
String lock = "";
synchronized(lock) {
//TODO
}
}