温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java中synchronized关键字的作用分析

发布时间:2021-07-01 15:18:53 来源:亿速云 阅读:416 作者:Leah 栏目:大数据

Java中synchronized关键字的作用分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

一、简介:

        synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。synchronized既可以加在一段代码上,也可以加在方法上。

1、举个栗子:

Java中synchronized关键字的作用分析

2、类文件编译

        看看该class文件的编译后的文件,查看当前类的包,变量信息,堆栈信息等等,有助于理解synchronized到底是什么指令操作的:

命令:javap -verbose MySynchronized > mySynchronized.txt

Java中synchronized关键字的作用分析

可以看到jvm加锁的指令,monitorenter加锁,monitorexit释放锁的指令,至于怎么计数的,有兴趣的可以深入研究一下。

二、synchronized的方式概念:

       类锁,对象锁,代码块锁,同步方法锁。

  1. 类锁:顾名思义是该类的锁,是初始化静态方法上的锁,与对象锁不一样,简单可以理解,类加载完就存在的锁。

  2. 对象锁:是new出来的实例,每个实例相互隔离。

  3. 方法锁:就是方法上加一个synchronized关键字,又区分为静态方法锁和实例方法锁,两者不一样。

  4. 代码块锁:就是锁一段代码,主要区别在括号里的对象synchronized(this){...},或者其他synchronized(lock){...}。

三、锁的几种用法和多线程下的阻塞分析

1、代码块锁,新建一个对象:Object lock = new Object(),这里锁的是这个对象的下的Object 对象,大部分人喜欢这样用,this是锁整个对象,范围比较大,可能造成该对象中其他加锁方法被干扰,所以可以用这种方式去防止大类对象被使用的时候造成死锁。

private Object lock = new Object();
/**
* 锁对象lock
*/
public void methodA(){
   synchronized(lock){
       System.out.println("methodA====start");
       try {
           Thread.sleep(2000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("methodA====end");
   }
}

2、代码块锁,锁类对象锁本身,不同的对象相互隔离,互不干扰。

/**
* 锁对象本身
*/
public void methodB(){
   synchronized(this){
       System.out.println("methodB==start");
       try {
           Thread.sleep(3000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("methodB==end");
   }
}

3、实例方法锁:

/**
* 实例方法锁,同一个实例,多线程阻塞
* 不同的实例,互不干扰,因为锁的不是一个对象
* 不同的实例,不同实例方法锁,多线程也是阻塞等待的,因为是一个对象
*/
public synchronized void methodD(){
   System.out.println("methodD==start");
   try {
       Thread.sleep(3000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
   System.out.println("methodD==end");
}

4、静态方法锁:

/**
* static方法,类级别的锁,更对象this无关,
* 同一个类中静态方法锁,多线程阻塞,等待获取类锁才能执行
* 同一个类中不同静态方法锁,多线程阻塞,也需要等待获取类锁才能执行
*/
public synchronized static void methodC(){
   System.out.println("methodC==start");
   try {
       Thread.sleep(3000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
   System.out.println("methodC==end");
}

5、最后说说wait和sleep和对象锁:

/**
* wait 会放弃对象锁,不会放弃CPU资源
* sleep 不会放弃对象锁,会放弃CPU资源
* 测试发现同一个对象,sleep的方法阻塞,wait方法会放弃对象 * 锁,继续多线程执行
*/
public synchronized void methodE(){
   System.out.println("methodE==start");
   try {
       this.wait(3000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
   System.out.println("methodE==end");
}

四、最后总结:

       主要看synchronized 锁的是不是同一个对象,是一个对象,则下一个线程则需要等待上一个线程释放对象锁,(记住是对象锁)

五、什么场景用?

        synchronized 虽然能保证线程安全,但是在并发场景下,会影响性能,比如在抢购场景下。还有加锁的方法或者加锁代码块是不是一个很耗时的流程,或者一个公共方法,很多业务逻辑都用到,这时候,并发环境下,基本行不通,不同的业务场景下不应该有干扰。所以尽量根据不同的场景和业务逻辑谨慎使用,也可以通过其他方式保证线程的安全,比如用并发包中的一些数据结构,或者ThreadLocal实现线程上下文变量一致性,防止其他程序对公共变量进行篡改。

六、扩展知识

1、很多人问,synchronized 和 实现Lock接口的对象都有加锁的功能,在开发的时候如何选择?

     《深入理解Java虚拟机》线程安全和锁优化一章有简单做介绍,synchronized 和ReentrantLock在JDK1.5 中单核,ReentrantLock比synchronized 的性能要好,多核CPU 下synchronized还是比ReentrantLock好,这样可以看出synchronized 的性能并不差,所以在JDK1.6,JVM在synchronized 的优化,性能已经由于Lock,在一般的synchronized 能满足需求的情况下会使用synchronized 。

2、那Lock又有哪些优势呢?

      synchronized 是java 的原生锁,而ReentrantLock是基于API的方式进行加锁的,和一些锁的其他操作。功能比synchronized 要强大,那就意味着用起来就灵活,可以实现很多synchronized 没有的功能,例如:

1.等待过程中,可以直接中断等待(如果一直没有获得锁的话)

2.公平锁:基于时间先后进行锁获取,不是synchronized 一样无序竞争。

3.一个ReentrantLock对象可以绑定多个锁对象,synchronized (Object)需要多个对象,而ReentrantLock只需多次调用newCondition()方法即可。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI