同步代码
需要同步的情况
- 当
多线程并发
,有多段
代码同时执行
时,希望某一段
代码执行的过程中
,CPU不要切换
到其他线程上,此时就需要同步。 - 如果有两段代码是同步进行的,那么
同一时间
只能执行其中一段
,在一段代码没执行结束之前
,不会执行另外一段
代码。
同步代码块操作
使用
synchronized
关键字加上一个锁对象
来定义一段代码
,这就称为同步代码块
。如果
多个同步代码块
使用同一个锁对象
,那么他们就是同步的
同步代码块是
锁机制
,同一个锁对象,同步代码块是同步的。锁对象是
任意对象
,但不能是匿名对象
,因为匿名对象不是同一个对象。当多个代码块使用了
同一个锁对象
的synchronized 锁机制
,只有当一个线程把 synchronized 代码块的代码全部执行完之后
,才能
去执行该同一锁对象的另一段代码
。- 即该多个代码块是
同步
的,同一时间只能执行其中一段
,执行完之后,才能执行另一段。 - 若
锁对象不一致
,即不是同步的
,会出现抢占线程执行的情况。
- 即该多个代码块是
具体操作:
public 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
关键字修饰一个方法
时,该方法中所有代码
都是同步的。//同步方法只需在方法上加 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
//同步方法只需在方法上加 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
,而是产生的字节码对象
public 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(); } }
- 静态域随着类的加载而加载,此时会产生该类的字节码对象,所以
同步方法和同步块,哪个是更好的选择
- 基本原则:
同步的范围越小越好
。 - 同步块之外的代码是异步执行的,比同步整个方法更有效率。