synchronized关键字

互斥同步是最常见的一种高并发正确性保障手段。同步是指多个线程并发访问共享数据时,保证共享数据在同一时刻只被一个线程使用,而互斥是实现同步的一种手段。

在Java中,最基本的互斥同步手段是synchronized关键字。

synchronized使用规则:

在Java中同步锁是依赖于对象存在的。不同线程对于同步锁是互斥的。例如一个线程拥有了这个对象的同步锁,则另外一个线程是拿不到的,除非这个线程释放了自己拿到的同步锁。
1, 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程访问该对象”的“synchronized方法”或者“synchronized代码块时将被阻塞。
2,当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程可以访问该对象的非同步代码块。
3,当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对该对象的其他synchronized方法或者代码块将被阻塞。

synchronized的两种使用方法:

1,同步代码块

class My_Thread implements Runnable{
	public  void run() {
		synchronized (this) {//this 锁住this对象
			for(int i = 0;i < 5;i++) {
				System.out.println(Thread.currentThread().getName()+" --进行-- "+i);	
			}
		}
		
	}
}
public class Test4 {
	public static void main(String[] args) {
		
		My_Thread my_Thread = new My_Thread();
		Thread thread = new Thread(my_Thread);
		thread.setName("t1");
		Thread thread1 = new Thread(my_Thread);
		thread1.setName("t2");
		thread.start();
		thread1.start();
	}
}

 

2,同步方法

class My_Thread implements Runnable{
	public synchronized void run() {//锁的是当前对象
			for(int i = 0;i < 5;i++) {
				System.out.println(Thread.currentThread().getName()+" --进行-- "+i);	
			}
		}
		
}
public class Test4 {
	public static void main(String[] args) {
		
		My_Thread my_Thread = new My_Thread();
		Thread thread = new Thread(my_Thread);
		thread.setName("t1");
		Thread thread1 = new Thread(my_Thread);
		thread1.setName("t2");
		thread.start();
		thread1.start();
	}
}

synchronized原理

class My_Thread implements Runnable{
	public  void run() {//锁的是当前对象
		synchronized (this) {
			for(int i = 0;i < 5;i++) {
				System.out.println(Thread.currentThread().getName()+" --进行-- "+i);	
			}
		}		
	}
}
public class Test4 {
	public static void main(String[] args) {
		
		My_Thread my_Thread = new My_Thread();
		Thread thread = new Thread(my_Thread);
		thread.setName("t1");
		Thread thread1 = new Thread(my_Thread);
		thread1.setName("t2");
		thread.start();
		thread1.start();
	}
}

我们对这段代码进行反编译

synchronized关键字经过编译之后,会在同步块前后分别形成monitorenter和monitorexit这两个字节码指令,这两个字节码都需要一个reference类型的参数来指明要锁定和解锁的对象。

在执行monitorenter时,首先要尝试获取对象的锁。如果这个对象没被锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数器加一,相应的。执行monitorexit时会将锁计数器减1,当计数器为0时就释放锁。如果获取对象锁失败,那么当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。(Java线程是映射到操作系统的原生线程上的,如果要阻塞或者唤醒一个线程,都需要操作系统帮忙完成,这就需要从 用户态转换到核心态中,因此状态转换需要耗费很多的处理器转换时间)所以synchronized也被称作重量级锁。

 

将同步代码块换成同步方法

class My_Thread implements Runnable{
	public synchronized void run() {//锁的是当前对象
		
			for(int i = 0;i < 5;i++) {
				System.out.println(Thread.currentThread().getName()+" --进行-- "+i);	
			}
				
	}
}

我们再来进行反编译

我们会发现在同步方法中并没有出现monitorenter和monitorexit这两个字节码指令。

同步方法是在Class文件的方法表中将该方法的access_flags字段中的synchronized标志位置设为1,表示该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象表示做为锁对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值