Java的Synchronized关键字学习指南(全面 & 详细)
前言
在Java中,有一个常被忽略但非常重要的关键字Synchronized今天,我将详细讲解Java关键字Synchronized的所有知识,希望你们会喜欢
目录
1.定义
Java中的1个关键字
2.作用
保证同一时刻最多只有1个线程执行被Synchronized修饰的方法/代码
其他线程必须等待当前线程执行完该方法/代码块后才能执行该方法/代码块
3.应用场景
保证线程安全,解决多线程中的并发同步问题(实现的是阻塞型并发),具体场景如下:
修饰实例方法/代码块时,(同步)保护的是同一个对象方法的调用&当前实例对象修饰静态方法/代码块时,(同步)保护的是静态方法的调用&class类对象
4.原理
依赖JVM实现同步底层通过一个监视器对象(monitor)完成,wait()、notify()等方法也依赖于monitor对象
监视器锁(monitor)的本质依赖于底层操作系统的互斥锁(MutexLock)实现
5.具体使用
Synchronized用于修饰代码块、类的实例方法&静态方法
5.1使用规则
5.2锁的类型&等级由于Synchronized会修饰代码块、类的实例方法&静态方法,故分为不同锁的类型具体如下
之间的区别
5.3使用方式
/**
*对象锁
*/
publicclassTest{
//对象锁:形式1(方法锁)
publicsynchronizedvoidMethod1(){
System.out.println("我是对象锁也是方法锁");
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
//对象锁:形式2(代码块形式)
publicvoidMethod2(){
synchronized(this){
System.out.println("我是对象锁");
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
/**
*方法锁(即对象锁中的形式1)
*/
publicsynchronizedvoidMethod1(){
System.out.println("我是对象锁也是方法锁");
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
/**
*类锁
*/
publicclassTest{
//类锁:形式1:锁静态方法
publicstaticsynchronizedvoidMethod1(){
System.out.println("我是类锁一号");
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
//类锁:形式2:锁静态代码块
publicvoidMethod2(){
synchronized(Test.class){
System.out.println("我是类锁二号");
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
5.4特别注意
Synchronized修饰方法时存在缺陷:若修饰1个大的方法,将会大大影响效率
示例
若使用Synchronized关键字修饰线程类的run(),由于run()在线程的整个生命期内一直在运行,因此将导致它对本类任何Synchronized方法的调用都永远不会成功
解决方案
使用Synchronized关键字声明代码块
该解决方案灵活性高:可针对任意代码块&任意指定上锁的对象
代码如下
synchronized(syncObject){
//访问或修改被锁保护的共享状态
//上述方法必须获得对象syncObject(类实例或类)的锁
}
6.特点
注:原子性、可见性、有序性的定义
7.其他控制并发/线程同步方式
7.1Lock、ReentrantLock简介
区别
7.2CAS
7.2.1定义
CompareAndSwap,即比较并交换,是一种解决并发操作的乐观锁
synchronized锁住的代码块:同一时刻只能由一个线程访问,属于悲观锁
7.2.2原理
//CAS的操作参数
内存位置(A)
预期原值(B)
预期新值(C)
//使用CAS解决并发的原理:
//1.首先比较A、B,若相等,则更新A中的值为C、返回True;若不相等,则返回false;
//2.通过死循环,以不断尝试尝试更新的方式实现并发
//伪代码如下
publicbooleancompareAndSwap(longmemoryA,intoldB,intnewC){
if(memoryA.get()==oldB){
memoryA.set(newC);
returntrue;
}
returnfalse;
}
7.2.3优点
资源耗费少:相对于synchronized,省去了挂起线程、恢复线程的开销
但,若迟迟得不到更新,死循环对CPU资源也是一种浪费
7.2.4具体实现方式使用CAS有个“先检查后执行”的操作而这种操作在Java中是典型的不安全的操作,所以CAS在实际中是由C++通过调用CPU指令实现的具体过程
//1.CAS在Java中的体现为Unsafe类 //2.Unsafe类会通过C++直接获取到属性的内存地址 //3.接下来CAS由C++的Atomic::cmpxchg系列方法实现
7.2.5典型应用:AtomicInteger
对i++与i–,通过compareAndSet&一个死循环实现
而compareAndSet函数内部=通过jni操作CAS指令。直到CAS操作成功跳出循环
privatevolatileintvalue;
/**
*Getsthecurrentvalue.
*
*@returnthecurrentvalue
*/
publicfinalintget(){
returnvalue;
}
/**
*Atomicallyincrementsbyonethecurrentvalue.
*
*@returnthepreviousvalue
*/
publicfinalintgetAndIncrement(){
for(;;){
intcurrent=get();
intnext=current+1;
if(compareAndSet(current,next))
returncurrent;
}
}
/**
*Atomicallydecrementsbyonethecurrentvalue.
*
*@returnthepreviousvalue
*/
publicfinalintgetAndDecrement(){
for(;;){
intcurrent=get();
intnext=current-1;
if(compareAndSet(current,next))
returncurrent;
}
}
8.总结
本文主要对Java中常被忽略但非常重要的关键字Synchronized进行讲解
到此这篇关于Java的Synchronized关键字学习指南的文章就介绍到这了,更多相关Java的Synchronized关键字内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。