【185期】面试官——你能说说 Synchronized实现对象锁的两种方式以及它的原理吗?

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 【185期】面试官——你能说说 Synchronized实现对象锁的两种方式以及它的原理吗?

点击上方“Java面试题精选”,关注公众号

面试刷图,查缺补漏

号外:往期面试题,10篇为一个单位归置到本公众号菜单栏-面试题,有需要的欢迎翻阅

阶段汇总集合:

一.同步代码块锁

案例:通过同步代码块锁,实现两个线程对同一个全局变量 count,各自执行1万次 count++,验证结果是否等于2万,而不会出现小于2万的情况。

完整代码实现:


public class SynchronizeCodeBlockLock implements Runnable {
 private static SynchronizeCodeBlockLock instance = new SynchronizeCodeBlockLock();
 private static int count = 0;

 @Override
 public void run() {
  method();
 }

 private void method() {
  // 关键:同步代码块的方式,操作同一变量,达到线程安全的效果
  synchronized (this) {
   System.out.println("线程名:" + Thread.currentThread().getName() + ",运行开始");
   for (int i = 0; i  10000; i++) {
    count++;
   }
   System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
  }
 }

 public static void main(String[] args) {
  Thread thread1 = new Thread(instance);
  Thread thread2 = new Thread(instance);
  thread1.start();
  thread2.start();
  while (thread1.isAlive() || thread2.isAlive()) {
   // 若有线程如果还在活动,则不执行下一步(等同于thread.join()方法)
  }
  System.out.println("期待结果:20000,实际结果:" + count);
 }


}

运行结果:


线程名:Thread-0,运行开始
线程:Thread-0,运行结束
线程名:Thread-1,运行开始
线程:Thread-1,运行结束
期待结果:20000,实际结果:20000

分析运行结果:

我们发现使用了 synchronized关键字后,线程Thread-0先执行,等到其结束后,Thread-1才开始执行。如果不使用 synchronized关键字,执行结果可能会是Thread-0和Thread-1几乎同时执行,几乎同时运行结束。这就说明使用了 synchronized关键字后,将多个线程的并行,变为了串行。

二.方法锁

本例仅展示方法锁,在控制线程串行执行的示例。方法锁保证线程安全的效果,跟同步代码块是一致的。


public class MethodLock implements Runnable {

 private static MethodLock instance = new MethodLock();

 @Override
 public void run() {
  method();
 }

 //关键:synchronized可以保证此方法被顺序执行,线程1执行完4秒钟后,线程2再执行4秒。不加synchronized,线程1和线程2将同时执行
 private synchronized void method() {
  System.out.println("线程:" + Thread.currentThread().getName() + ",运行开始");
  try {
   //模拟执行一段操作,耗时4秒钟
   Thread.sleep(4000);
   System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }

 public static void main(String[] args) {
  // 模拟:同一个对象下,两个线程,同步执行一个方法(串行执行则为线程安全,并行执行,则为线程不安全,)
  Thread thread1 = new Thread(instance);
  Thread thread2 = new Thread(instance);
  thread1.start();
  thread2.start();
  while (thread1.isAlive() || thread2.isAlive()) {

  }
  System.out.println("测试结束");
 }
}

运行结果:


线程:Thread-0,运行开始
线程:Thread-0,运行结束
线程:Thread-1,运行开始
线程:Thread-1,运行结束
测试结束

发现运行结果中,多个线程也是串行执行的,效果跟同步代码块锁是一致的。

往期面试题汇总:

三.synchronized关键字,是怎么保证线程安全的呢?

在Java中所有的对象,都会有一把锁,叫做内置锁,也称作监视器锁。这是种排他锁。

排他锁:一个线程获取后,其他线程只能等待其释放后,才有机会获得该锁。

Java中每个对象,都可以把内置锁,当做一个同步锁来使用。当一个线程在进入到 synchronized代码块前时,会自动获取到监视器锁,此时其他线程在访问 synchronized代码块时,就会被堵塞挂起(被拒之门外的意思)。拿到锁的线程会在执行完成、或者抛出异常、或者调用wait系列方法时释放该锁。其他线程只能等待锁被释放后才能获取该锁。

通俗的讲, synchronized关键字将代码块中代码由 并行转变成了 串行,这样就保证了代码被顺序执行。

四.synchronized在内存层面,是如何实现加锁和释放锁的?

  • 进入`synchronized`代码块时,会将代码块内用到的变量从该线程的工作内存中清除,转而从主内存中获取。
  • 退出`synchronized`代码块时,会将代码块内用到的变量的修改,刷新到主内存中。
  • 这其实就是 synchronized解决共享变量 内存可见性的原理。关于 synchronized的性质(可见性、可重入性),我会在后续其他文章中详细解释。

    五.synchronized将线程的并行处理转为串行处理,有什么缺点?

    synchronized将并行改为串行,当然会影响程序的执行效率,执行速度会受到影响。其次, synchronized操作线程的堵塞,也就是由操作系统控制CPU的内核进行上下文的切换,这个切换本身也是耗时的。所以使用 synchronized关键字会降低程序的运行效率。

    六. 使用Synchronized关键字需要注意什么?

    1.Synchronized使用时需要注意的地方锁对象不能为空。

    锁对象的信息是保留在对象头中的,如果对象为空,则锁的信息也就不存在了。

    2.作用域不宜过大

    synchronized代码块的代码量不宜过多,如果把过多的代码放在其中,程序的运行会变为串行,速度会下降。各个线程并行可以提高效率,我们应该仅把那些影响线程安全的代码,放入synchronized代码块中,串行执行;不需要考虑线程安全的代码,并行执行,达到效率最高。

    3.避免死锁

    避免让线程对锁持有并等待的情况出现(后续文章将讲解死锁的相关知识)。

    七.总结

    本文讲解了Java中的对象锁的两种实现方式,分别是以下两种实现形式:

    方式一:同步代码块锁:

    
    synchronized (共享变量) {
        //需要同步的代码
    }
    

    方式二:方法锁:

    
     private synchronized void method() {
         //需要同步的代码
     }
    

    无论你使用哪一种形式,都应该在保证同步的情况下,尽量减少同步代码的内容,这样可以提高程序的运行效率,还能保证线程的安全。

    来源:blog.csdn.net/x541211190/article/details/106179245

    与其在网上拼命找题?** 不如马上关注我们~**

    【185期】面试官:你能说说 Synchronized实现对象锁的两种方式以及它的原理吗?

    原文始发于微信公众号(Java面试题精选):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> 【185期】面试官——你能说说 Synchronized实现对象锁的两种方式以及它的原理吗?


     上一篇
    SQL数据库面试题以及答案(50例题) SQL数据库面试题以及答案(50例题)
    点击上方“Java面试题精选”,关注公众号 面试刷图,查缺补漏 号外:往期面试题,10篇为一个单位归置到本公众号菜单栏-面试题,有需要的欢迎翻阅 阶段汇总集合: 没有给出回答的问题,欢迎留言区补充~~ Student(Sid,Sname,S
    2021-04-05
    下一篇 
    【186期】一口气说出 Synchronized 同步方法的八种使用场景 【186期】一口气说出 Synchronized 同步方法的八种使用场景
    点击上方“Java面试题精选”,关注公众号 面试刷图,查缺补漏 号外:往期面试题,10篇为一个单位归置到本公众号菜单栏-面试题,有需要的欢迎翻阅 阶段汇总集合: 简介本文将介绍7种同步方法的访问场景,我们来看看着七种情况下,多线程访问同步方
    2021-04-05