让每一名学员高薪就业
返回列表 发新帖

Java多线程中易混淆的3个关键字

[复制链接]

190

主题

200

帖子

1953

积分

精英

Rank: 5Rank: 5

积分
1953
发表于 2019-1-21 09:47:42  | 显示全部楼层 | 阅读模式
本文主要介绍了Java多线程编程中易混淆的3个关键字总结,本文总结了:volatile、ThreadLocal、synchronized等3个关键字,对这几个容易混淆概念的关键字分别做了讲解。
1.volatile
volatile主要是用来在多线程中同步变量。
在一般情况下,为了提升性能,每个线程在运行时都会将主内存中的变量保存一份在自己的内存中作为变量副本,但是这样就很容易出现多个线程中保存的副本变量不一致,或与主内存的中的变量值不一致的情况。
而当一个变量被volatile修饰后,该变量就不能被缓存到线程的内存中,它会告诉编译器不要进行任何移出读取和写入操作的优化,换句话说就是不允许有 不同于“主”内存区域的变量拷贝,所以当该变量有变化时,所有调用该变量的线程都会获得相同的值,这就确保了该变量在应用中的可视性(当一个任务做出了修 改在应用中必须是可视的),同时性能也相应的降低了(还是比synchronized高)。
但需要注意volatile只能确保操作的是同一块内存,并不能保证操作的原子性。所以volatile一般用于声明简单类型变量,使得这些变量具有原子 性,即一些简单的赋值与返回操作将被确保不中断。但是当该变量的值由自身的上一个决定时,volatile的作用就将失效,这是由volatile关键字 的性质所决定的。
所以在volatile时一定要谨慎,千万不要以为用volatile修饰后该变量的所有操作都是原子操作,不再需要synchronized关键字了。
2.ThreadLocal
首先ThreadLocal和本地线程没有关系,更不是一个特殊的Thread,它只是一个线程的局部变量(其实就是一个 Map),ThreadLocal会为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的 副本。这样做其实就是以空间换时间的方式(与synchronized相反),以耗费内存为代价,单大大减少了线程同步(如synchronized)所 带来性能消耗以及减少了线程并发控制的复杂度。
个人觉得比较典型的例子就是在Android关于Looper的源码中对ThreadLocal的使用,同时也包含了ThreadLocal的基本用法,具体代码如下:
代码清单1


  1. public class Looper {

  2. private static final String TAG = "Looper";

  3. //sThreadLocal.get() will return null unless you've called prepare().

  4. private static final ThreadLocal sThreadLocal = new ThreadLocal();

  5. ......

  6. private static Looper mMainLooper = null; s

  7. ......

  8. public static final void prepare() {

  9.      if (sThreadLocal.get() != null) {

  10.        throw new RuntimeException("Only one Looper may be created per thread");

  11.      }

  12.      sThreadLocal.set(new Looper());

  13. }

  14. ......

  15. public static final void prepareMainLooper() {

  16.      prepare();

  17.      setMainLooper(myLooper());

  18.      ......

  19. }

  20. private synchronized static void setMainLooper(Looper looper) {

  21.       mMainLooper = looper;

  22. }

  23. public synchronized static final Looper getMainLooper() {

  24.       return mMainLooper;

  25. }

  26. ......

  27. public static final Looper myLooper() {

  28.       return (Looper)sThreadLocal.get();

  29. }

  30. ......

  31. }
复制代码
但需要注意的是,虽然ThreadLocal和Synchonized都用于解决多线程并发访问,ThreadLocal与synchronized还是 有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变 量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多 个线程间通信时能够获得数据共享。即Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。所以 ThreadLocal并不能代替synchronized,Synchronized的功能范围更广(同步机制)。
3.synchronized
synchronized关键字是Java利用锁的机制自动实现的,一般有同步方法和同步代码块两种使用方式。Java中所有的对象都自动含有单一 的锁(也称为监视器),当在对象上调用其任意的synchronized方法时,此对象被加锁(一个任务可以多次获得对象的锁,计数会递增),同时在线程 从该方法返回之前,该对象内其他所有要调用类中被标记为synchronized的方法的线程都会被阻塞。当然针对每个类也有一个锁(作为类的Class 对象的一部分)。
最后需要注意的是synchronized是同步机制中最安全的一种方式,其他的任何方式都是有风险的,当然付出的代价也是最大的。

回复

使用道具 举报

0

主题

10

帖子

-1

积分

限制会员

积分
-1
发表于 2019-1-21 09:53:58  | 显示全部楼层
我逐字逐句地看完这个帖子
回复 支持 反对

使用道具 举报

0

主题

10

帖子

4

积分

菜鸟

Rank: 1

积分
4
发表于 2019-1-21 09:56:56  | 显示全部楼层
源码的老师最棒!
回复 支持 反对

使用道具 举报

0

主题

17

帖子

-5

积分

限制会员

积分
-5
发表于 2019-1-21 09:57:16  | 显示全部楼层
我要把这个帖子一直往上顶!
回复 支持 反对

使用道具 举报

0

主题

13

帖子

5

积分

菜鸟

Rank: 1

积分
5
发表于 2019-1-21 09:57:19  | 显示全部楼层
大家都来撩源妹儿!
回复 支持 反对

使用道具 举报

0

主题

16

帖子

5

积分

菜鸟

Rank: 1

积分
5
发表于 2019-1-21 09:57:29  | 显示全部楼层
源码的老师最棒!
回复 支持 反对

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Java培训  |   PHP培训  |   UI培训  |   H5培训  |   Python培训  |   大数据培训  |   如何报名  |   视频下载
快速回复 返回顶部 返回列表