同步代码
需要同步的情况
- 当
多线程并发
,有多段
代码同时执行
时,希望某一段
代码执行的过程中
,CPU不要切换
到其他线程上,此时就需要同步。 - 如果有两段代码是同步进行的,那么
同一时间
只能执行其中一段
,在一段代码没执行结束之前
,不会执行另外一段
代码。
同步代码块操作
使用
synchronized
关键字加上一个锁对象
来定义一段代码
,这就称为同步代码块
。如果
多个同步代码块
使用同一个锁对象
,那么他们就是同步的
同步代码块是
锁机制
,同一个锁对象,同步代码块是同步的。锁对象是
任意对象
,但不能是匿名对象
,因为匿名对象不是同一个对象。当多个代码块使用了
同一个锁对象
的synchronized 锁机制
,只有当一个线程把 synchronized 代码块的代码全部执行完之后
,才能
去执行该同一锁对象的另一段代码
。- 即该多个代码块是
同步
的,同一时间只能执行其中一段
,执行完之后,才能执行另一段。 - 若
锁对象不一致
,即不是同步的
,会出现抢占线程执行的情况。
- 即该多个代码块是
具体操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public class SynchronizeTest {
public static void main(String[] args) {
Consumer con = new Consumer();
new Thread(()->{
while(true)
con.print1();
}).start();
new Thread(()->{
while(true)
con.print2();
}).start();
}
}
class Consumer {
//定义一个Object对象,作为锁对象
Object obj = new Object();
public void print1(){
//锁机制使用同一个锁对象
synchronized (obj){
System.out.print("同");
System.out.print("步");
System.out.print("代");
System.out.print("码");
System.out.print("块");
System.out.println();
}
}
public void print2(){
//锁机制使用同一个锁对象,作为同步代码块
synchronized(obj){
System.out.print("多");
System.out.print("线");
System.out.print("程");
System.out.println();
}
}
}
同步方法
使用
synchronized
关键字修饰一个方法
时,该方法中所有代码
都是同步的。1
2
3
4
5
6
7
8
9
10
11
12//同步方法只需在方法上加 synchronized
public synchronized void print1(){
//锁机制使用同一个锁对象
synchronized (obj){
System.out.print("同");
System.out.print("步");
System.out.print("代");
System.out.print("码");
System.out.print("块");
System.out.println();
}
}
非静态同步函数
的锁是this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//同步方法只需在方法上加 synchronized
public synchronized void print1(){
System.out.print("同");
System.out.print("步");
System.out.print("代");
System.out.print("码");
System.out.print("块");
System.out.println();
}
public void print2(){
//非静态的同步方法的锁对象是this
synchronized(this){
System.out.print("多");
System.out.print("线");
System.out.print("程");
System.out.println();
}
}此时 这两个方法时 同步的
静态同步函数
的锁是字节码对象
- 静态域随着类的加载而加载,此时会产生该类的字节码对象,所以
静态
同步方法锁对象不能是this
,而是产生的字节码对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public static synchronized void print1(){
System.out.print("同");
System.out.print("步");
System.out.print("代");
System.out.print("码");
System.out.print("块");
System.out.println();
}
public static void print2(){
//静态的同步方法的锁对象是随着类加载而产生的类的字节码对象
synchronized(Customer.class){
System.out.print("多");
System.out.print("线");
System.out.print("程");
System.out.println();
}
}- 静态域随着类的加载而加载,此时会产生该类的字节码对象,所以
同步方法和同步块,哪个是更好的选择
- 基本原则:
同步的范围越小越好
。 - 同步块之外的代码是异步执行的,比同步整个方法更有效率。