synchronized入门详解

一、synchronized的使用
二、synchronized的实现原理
三、锁的升级过程

一、synchronized的使用
synchronized是Java提供的用于线程同步的锁机制,使用synchronized关键字可以有效解决线程同步的原子性和可见性问题。
原子性是指保证某些临界代码只能同时由一个线程执行
可见性是指线程对共享资源的修改可以及时让其他线程见到(即刷新值回主存中,并通知其他线程)

1、synchronized的用法:
1.1修饰代码块(锁当前对象,调用该方法的对象会获得锁)
1.2修饰实例方法(锁当前对象,调用该方法的对象会获得锁)
1.3修饰静态方法(锁的是该类对象:类名.class;调用该类的对象会获得锁)
1.4修饰类(锁的是该类对象:类名.class,调用该类的对象会获得锁)

package com.djn.Thread;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SynchronizedDemo {
	private static int count=0;
	private static final int THREAD_NUMBER=5; //线程数量
	private static final int REQUEST_NUMBER=100; //模拟并发数量
	
	public void add() {
		//1.修饰代码块
		synchronized (this) {
			count++;
		}
	}
	public synchronized void add1() {
		//2.修饰方法
		count++;
	}
	public static synchronized void add2() {
		//3.修饰静态方法
		count++;
	}
	public  void add3() {
		//4.修饰类
		synchronized (this.getClass()) {
			count++;
		}
	}

	public static void main(String[] args) {
		/*
		 * synchronized的四种用法
		 * 1、修饰代码块(锁当前this对象)
		 * 2、修饰实例方法(锁当前this对象)
		 * 3、修饰静态方法(锁类对象:类名.class)
		 * 4、修饰类(锁类对象:类名.class)
		 */
		SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
		ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUMBER);
		CountDownLatch countDownLatch = new CountDownLatch(REQUEST_NUMBER);
		for(int i=1; i<=REQUEST_NUMBER; i++) {
			executorService.execute(new Runnable() {
				
				@Override
				public void run() {
					synchronizedDemo.add();
					countDownLatch.countDown();
					
				}
			});
		}
		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		finally {
			executorService.shutdown();
			System.out.println(count);
		}
	}
}

2、synchronized保证可见性的原因
因为在线程获取锁时(即进入临界区时),会强制到内存当中获取最新的共享数据,当释放锁时,会将修改后的值重新刷新到内存当中。

二、synchronized的实现原理

那么synchronized的底层是怎么实现的呢?
我们先来了解一下java对象的内存布局(java object layout 即jol)
在这里插入图片描述
markword:标记对象的锁状态等(属于对象头:gc、hashcode和锁信息
类元信息指针:指向方法区中类元信息的指针
实例数据:存放对象的成员变量
对齐填充:将对象的字节数补充到8的整数倍

当使用synchronized给对象上锁时,就是将当前调用该方法的线程的信息存入到对象的markword当中,当有另外一个线程需要调用这个对象的方法时,如果该对象markword中已经有其他线程信息,则这个线程会停下来。这就是锁的原理,依赖于jvm。
现在看synchronized的四种用法,实际上只有两种,一种是锁实例对象的markword(对该实例对象有效),一种是锁类对象(对所有实现该类的对象有效)

三、锁升级的过程
知道了synchronized的锁原理,现在我们来聊一下锁升级过程
在这里插入图片描述
偏向锁:就是在对象的markword上标记了某一线程(即偏向于这个线程)
轻量级锁:即自旋锁(CAS),当有多个线程竞争锁时,一个线程获得锁,其他线程处于自旋状态
重量级锁:当有多个线程获得锁,一个线程获得锁,其他线程放入阻塞队列当中
匿名偏向:在新建对象之前,jvm的偏向锁已经启动(默认启动,但会有延迟,一般会在jvm启动4秒之后启动偏向锁),这时候新建对象则会直接为该对象上偏向锁。

在控制台上输入
java -XX:+PrintFlagsFinal -version
查看jvm的参数
在这里插入图片描述
锁的升级过程:
当只有一个线程访问synchronized时,会在该对象的markword上标记当前线程,成为偏向锁,当再有线程访问时,两个线程会竞争markword上的位置,这时候便成为自旋锁(即轻量锁),当并发数量很多的时候,便会成为重量级锁。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值