synchronized关键字

Synchronized关键简介

Java并发编程中,Synchronized关键字是一种避免多线程同时操作对象中实例变量出现线程安全的方法。

Synchronized取得的锁都是对象锁,而不是把一段代码或者方法当做锁。

多个对象多个锁

HasNum.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class HasNum {
private int num = 0;

synchronized public void add(String userName){
try {
if (userName.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000);
}else{
num = 200;
System.out.println("b set over");
}
System.out.println(userName + "set num = "+ num);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

ThreadA.java

1
2
3
4
5
6
7
8
9
10
11
12
public class ThreadA extends Thread {
private HasNum hasNum;

public ThreadA(HasNum hasNum){
this.hasNum = hasNum;
}

public void run(){
super.run();
hasNum.add("a");
}
}

ThreadB.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ThreadB extends Thread{
private HasNum hasNum;

public ThreadB(HasNum hasNum){
this.hasNum = hasNum;
}

public void run(){
super.run();
hasNum.add("b");
}

public static void main(String[] args) {
HasNum hasNumA = new HasNum();
HasNum hasNumB = new HasNum();
ThreadA threadA = new ThreadA(hasNumA);
ThreadB threadB = new ThreadB(hasNumB);
threadA.start();
threadB.start();
}
}

运行结果:

aset num = 100要停顿一会才会执行。

1736

上述主方法中创建了两个HasNum对象,Synchronized取得是对象锁,,所以产生了两个锁。在ThreadA执行到Thread.sleep(2000)的时候,线程睡眠,所以aset Num = 100 会停顿一会才能执行。

但是如果把主函数中改为:

1
2
3
4
5
6
7
public static void main(String[] args) {
HasNum hasNum = new HasNum();
ThreadA threadA = new ThreadA(hasNum);
threadA.start();
ThreadB threadB = new ThreadB(hasNum);
threadB.start();
}

运行结果:

1746

这样就是两个线程共用一个对象,在ThreadA取得hasNum对象的时候,ThreadB在ThreadA执行完成以前都不能执行。同样的aset num = 100会等待一段时间执行。

Synchronized锁重入

可重入锁的概念是:自己可以再次获得自己的内部锁。比如所一个线程的方法获得了一个对象的锁,这个时候对象的锁是还没有释放的,此时想要再次获得这个对象的锁还是可以获得的,这就是可重入锁。如果是不可重入锁的话,就会造成死锁。

Service.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Service {
synchronized public void service1(){
System.out.println("service1");
service2();
}

synchronized public void service2(){
System.out.println("service2");
service3();
}

synchronized public void service3(){
System.out.println("service3");
}
}

MyThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyThread extends Thread {
@Override
public void run() {
super.run();
Service service = new Service();
service.service1();
}

public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}

运行结果:

2135

另外可重入锁也支持在父子继承的关系中