前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java多线程问题汇总

Java多线程问题汇总

原创
作者头像
李林LiLin
修改2023-04-01 16:39:14
3530
修改2023-04-01 16:39:14
举报
文章被收录于专栏:Android进阶编程

1、线程中start()、run(),wait()、sleep(),sleep() 、join()、yield()有什么区别?

1.1、线程中start和run方法有什么区别

  • 调用start()方法时会执行run()方法,不能直接调用run()方法。调用start()方法时将创建新的线程,并且执行在run()方法里的代码。但是直接调用run()方法,不会创建新的线程也不会执行调用线程的代码。

1.2、wait和sleep方法的不同

  • 让当前执行线程陷入等待(注意:不一定是调用wait方法的线程,也就是执行这行代码的线程),在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

1.3、sleep()方法

  • 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 让其他线程有机会继续执行,但它并不释放对象锁。也就是如果有Synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕获异常。
  • 比如有两个线程同时执行(没有Synchronized),一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完成后,低优先级的线程才能执行;但当高优先级的线程sleep(5000)后,低优先级就有机会执行了。sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。

1.4、yield()方法

  • yield()方法和sleep()方法类似,它没有参数,也不会释放“锁标志”只是提出申请释放CPU资源,至于能否成功释放由JVM决定。即yield()方法只是使当前线程重新回到可执行状态(RUNNABLE),所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。

1.5、join()方法

  • t.join()的意思是阻塞当前线程(即执行t.join()这条语句的线程),直到线程t完成,此线程再继续。
  • join之所以可以实现线程等待是因为调用wait方法。
  • Thread的join()有什么作用?

1.6、Thread.sleep(0)的作用是啥?

  • 由于Java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取到CPU控制权的情况,为了让某些优先级比较低的线程也能获取到CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作,这也是平衡CPU控制权的一种操作。

2、ReentrantLock和synchronized的区别

2.1、保障线程安全有哪些手段,可从多线程三特性出发:

  • 原子性(Atomicity):单个或多个操作是要么全部执行,要么都不执行
    • Lock:保证同时只有一个线程能拿到锁,并执行申请锁和释放锁的代码
    • synchronized:对线程加独占锁,被它修饰的类/方法/变量只允许一个线程访问
  • 可见性(Visibility):当一个线程修改了共享变量的值,其他线程能够立即得知这个修改
    • volatile:保证新值能立即同步到主内存,且每次使用前立即从主内存刷新;
    • synchronized:在释放锁之前会将工作内存新值更新到主存中
  • 有序性(Ordering):程序代码按照指令顺序执行
    • volatile: 本身就包含了禁止指令重排序的语义
    • synchronized:保证一个变量在同一个时刻只允许一条线程对其进行lock操作,使得持有同一个锁的两个同步块只能串行地进入

2.2、ReentrantLock和synchronized的区别

  • ReentrantLock:
    • 等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。
    • 公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。而synchronized是非公平的,即在锁被释放时,任何一个等待锁的线程都有机会获得锁。ReentrantLock默认情况下也是非公平的,但可以通过带布尔值的构造函数改用公平锁
    • 锁绑定多个条件:一个ReentrantLock对象可以通过多次调用newCondition()同时绑定多个Condition对象。而在synchronized中,锁对象wait()和notify()或notifyAl()只能实现一个隐含的条件,若要和多于一个的条件关联不得不额外地添加一个锁。
  • Synchronized:
    • 是悲观锁机制,独占锁。而Locks.ReentrantLock是每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。

2.3、ReentrantLock适用场景

  • 某个线程在等待一个锁的控制权的这段时间需要中断
  • 需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁可以绑定多个条件。
  • 具有公平锁功能,每个到来的线程都将排队等候。

3、Volatile和Synchronized的区别

3.1、Volatile和Synchronized各自用途是什么?有哪些不同点?

  • 粒度不同,前者针对变量 ,后者锁对象和类。
  • Synchronized阻塞,volatile线程不阻塞。
  • Synchronized保证三大特性(原子性、可见性、有序性),volatile不保证原子性
  • Synchronized编译器优化,volatile不优化,volatile具备两种特性:
    • 保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的。
    • 禁止指令重排序优化。
  • Volatile如何保证内存可见性:
    • 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
    • 当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

3.2、Synchronize在编译时如何实现锁机制?

  • Synchronized经过编译,会在同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。

3.3、用volatile修饰,多线程去操作++,线程安全吗?那如何才能保证i++线程安全?

  • 不安全
    • volatile只能保证可见性,并不能保证原子性
    • i++实际上会被分成多步完成:
      • 获取i的值;
      • 执行i+1;
      • 将结果赋值给i。
    • volatile只能保证这3步不被重排序,多线程情况下,可能两个线程同时获取i,执行i+1,然后都赋值结果2,实际上应该进行两次+1操作。
  • 如何才能保证i++线程安全
    • 可以使用java.util.concurrent.atomic包下的原子类,如AtomicInteger。其实现原理是采用CAS自旋操作更新值。

4、CAS原理

4.1、CAS原理是什么

  • CAS即compare and swap的缩写,中文翻译成比较并交换。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。自旋就是不断尝试CAS操作直到成功为止。

4.2、CAS实现原子操作会出现什么问题

  • ABA问题。因为CAS需要在操作之的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成,有变成A,那么使用CAS进行检查时会发现它的值没有发生变化,但实际上发生了变化。ABA问题可以通过添加版本号来解决。Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。
  • 循环时间长开销大。pause指令优化。
  • 只能保证一个共享变量的原子操作。可以合并成一个对象进行CAS操作。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、线程中start()、run(),wait()、sleep(),sleep() 、join()、yield()有什么区别?
    • 1.1、线程中start和run方法有什么区别
      • 1.2、wait和sleep方法的不同
        • 1.3、sleep()方法
          • 1.4、yield()方法
            • 1.5、join()方法
              • 1.6、Thread.sleep(0)的作用是啥?
              • 2、ReentrantLock和synchronized的区别
                • 2.1、保障线程安全有哪些手段,可从多线程三特性出发:
                  • 2.2、ReentrantLock和synchronized的区别
                    • 2.3、ReentrantLock适用场景
                    • 3、Volatile和Synchronized的区别
                      • 3.1、Volatile和Synchronized各自用途是什么?有哪些不同点?
                        • 3.2、Synchronize在编译时如何实现锁机制?
                          • 3.3、用volatile修饰,多线程去操作++,线程安全吗?那如何才能保证i++线程安全?
                          • 4、CAS原理
                            • 4.1、CAS原理是什么
                              • 4.2、CAS实现原子操作会出现什么问题
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档