同步代码
需要同步的情况
- 当
多线程并发,有多段代码同时执行时,希望某一段代码执行的过程中,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();
}
}
非静态同步函数的锁是this1
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();
}
}- 静态域随着类的加载而加载,此时会产生该类的字节码对象,所以
同步方法和同步块,哪个是更好的选择
- 基本原则:
同步的范围越小越好。 - 同步块之外的代码是异步执行的,比同步整个方法更有效率。