synchronized锁介绍
synchronized是Java的一个关键字。来自官方的解释:Synchronized方法支持一种简单的策略,用于防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读或写操作都通过Synchronized方法完成。
synchronized锁的特性
Synchronized保证同一时刻有且只有一条线程在操作共享数据,其他线程必须等待该线程处理完数据后再对共享数据进行操作。此时便产生了互斥锁,互斥锁的特性如下:
互斥性:即在同一时刻只允许一个线程持有某个对象锁,通过这种特性来实现多线程协调机制,这样在同一时刻只有一个线程对所需要的同步的代码块(复合操作)进行访问。互斥性也成为了操作的原子性。
可见性:必须确保在锁释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程可见(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作,从而引起数据不一致。
Synchronized是最基本的互斥手段,保证同一时刻最多只有1个线程执行被Synchronized修饰的方法 / 代码,其他线程 必须等待当前线程执行完该方法 / 代码块后才能执行该方法 / 代码块。
synchronized有三种应用场景
- 对于普通同步方法,锁是当前实例对象。
- 对于静态同步方法,锁是当前类的Class对象。
- 对于同步方法块,锁是Synchronized括号里配置的对象。
1.synchronized方法用作对象锁时:
下面看一段测试用例,一共创建了三个类
Person类(初始状态下都不加锁)
package bingfa;
public class Person {
public volatile int age;
public String name;
public void m1() {
System.out.println("m1方法开始");
try {
Thread.sleep(2000);
} catch (Exception e) {}
System.out.println("m1方法结束");
}
public void m2() {
System.out.println("m2方法开始");
try {
Thread.sleep(2000);
} catch (Exception e) {}
System.out.println("m2方法结束");
}
public static void m3() {
System.out.println("m3方法开始");
try {
Thread.sleep(2000);
} catch (Exception e) {}
System.out.println("m3方法结束");
}
public static void m4() {
System.out.println("m4方法开始");
try {
Thread.sleep(2000);
} catch (Exception e) {}
System.out.println("m4方法结束");
}
}
ThreadTest类
package bingfa;
public class ThreadPlus extends Thread{
private Person m;
private int flag;
public ThreadPlus(Person x, int w) {
m = x;
flag = w;
}
@Override
public void run() {
if(flag == 1) {
m.m1();
}else {
m.m2();
}
}
}
主方法类
package bingfa;
public class Test {
public static void main(String[] args) throws Exception{
Person x1 = new Person();
Person x2 = new Person();
//====================================================
ThreadPlus t1 = new ThreadPlus(x1,1);
ThreadPlus t2 = new ThreadPlus(x1,2);
t1.start();
t2.start();
//=======
t1.join();
t2.join();
}
}
然后我们使用synchronized关键字分别进行测试
m1,m2方法都不加锁
这时m1,m2两个线程可以同时执行
m1加锁
只有一个方法加锁,不构成互斥条件,因此m1,m2两个方法也互不影响,自由执行。
m1,m2同时加锁
这是构成了互斥条件,同一时刻,m1和m2只能有一个正在执行。
2.synchronized方法用作类锁时:
修饰的static静态方法,与上面作为对象锁时类似,只有两个静态方法同时加锁,才构成互斥条件,二者不能同时执行,其余互不干扰
也就是说只有类型相同时互斥,静态和非静态之间互不干扰。
3.修饰代码块
需要注意的是,synchronized只能锁引用类型,而不能锁基本类型