Java多线程中易混淆的概念
概述
最近在看《ThinKing In Java》,看到多线程章节时觉得有一些概念比较容易混淆有必要总结一下,虽然都不是新的东西,不过还是蛮重要,很基本的,在开发或阅读源码中经常会遇到,在这里就简单的做个总结。
1.volatile
volatile主要是用来在多线程中同步变量。
在一般情况下,为了提升性能,每个线程在运行时都会将主内存中的变量保存一份在自己的内存中作为变量副本,但是这样就很容易出现多个线程中保存的副本变量不一致,或与主内存的中的变量值不一致的情况。
而当一个变量被volatile修饰后,该变量就不能被缓存到线程的内存中,它会告诉编译器不要进行任何移出读取和写入操作的优化,换句话说就是不允许有不同于“主”内存区域的变量拷贝,所以当该变量有变化时,所有调用该变量的线程都会获得相同的值,这就确保了该变量在应用中的可视性(当一个任务做出了修改在应用中必须是可视的),同时性能也相应的降低了(还是比synchronized高)。
但需要注意volatile只能确保操作的是同一块内存,并不能保证操作的原子性。所以volatile一般用于声明简单类型变量,使得这些变量具有原子性,即一些简单的赋值与返回操作将被确保不中断。但是当该变量的值由自身的上一个决定时,volatile的作用就将失效,这是由volatile关键字的性质所决定的。
所以在volatile时一定要谨慎,千万不要以为用volatile修饰后该变量的所有操作都是原子操作,不再需要synchronized关键字了。
2.ThreadLocal
首先ThreadLocal和本地线程没有一毛钱关系,更不是一个特殊的Thread,它只是一个线程的局部变量(其实就是一个Map),ThreadLocal会为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这样做其实就是以空间换时间的方式(与synchronized相反),以耗费内存为代价,单大大减少了线程同步(如synchronized)所带来性能消耗以及减少了线程并发控制的复杂度。
个人觉得比较典型的例子就是在Android关于Looper的源码中对ThreadLocal的使用,同时也包含了ThreadLocal的基本用法,具体代码如下:
public class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
private static final ThreadLocal sThreadLocal = new ThreadLocal();
......
private static Looper mMainLooper = null;
......
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
......
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
......
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
public synchronized static final Looper getMainLooper() {
return mMainLooper;
}
......
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
......
}
但需要注意的是,虽然ThreadLocal和Synchonized都用于解决多线程并发访问,ThreadLocal与synchronized还是有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。即Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。所以ThreadLocal并不能代替synchronized,Synchronized的功能范围更广(同步机制)。
3.synchronized
synchronized关键字是Java利用锁的机制自动实现的,一般有同步方法和同步代码块两种使用方式。Java中所有的对象都自动含有单一的锁(也称为监视器),当在对象上调用其任意的synchronized方法时,此对象被加锁(一个任务可以多次获得对象的锁,计数会递增),同时在线程从该方法返回之前,该对象内其他所有要调用类中被标记为synchronized的方法的线程都会被阻塞。当然针对每个类也有一个锁(作为类的Class对象的一部分),所以你懂的.。
最后需要注意的是synchronized是同步机制中最安全的一种方式,其他的任何方式都是有风险的,当然付出的代价也是最大的。
Java多线程中易混淆的概念的更多相关文章
- .NET 中易混淆的概念(Delegate vs Event)
事件(event)是一个非常重要的概念,我们的程序时刻都在触发和接收着各种事件:鼠标点击事件,键盘事件,以及处理操作系统的各种事件.所谓事件就是 由某个对象发出的消息.比如用户按下了某个按钮,某个文件 ...
- JQuery中易混淆的概念
append(): 向每个匹配的元素内部追加内容. <p>I would like to say: </p> $("p").append("< ...
- Java多线程中的竞争条件、锁以及同步的概念
竞争条件 1.竞争条件: 在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象.这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作 ...
- java多线程中并发集合和同步集合有哪些?区别是什么?
java多线程中并发集合和同步集合有哪些? hashmap 是非同步的,故在多线程中是线程不安全的,不过也可以使用 同步类来进行包装: 包装类Collections.synchronizedMap() ...
- java 多线程研究:锁的概念
java多线程:锁 java的多线程中的锁是干嘛的呢?在网上找了很多博客,大都是很专业的语言,让我一时间摸不着头脑.下面分三个部分来总结多线程中的锁的概念. 一,基础概念: 多线程在运行的时候可能会遇 ...
- C#中易混淆的知识点
C#中易混淆的知识点 一.引言 今天在论坛中看到一位朋友提出这样的一个问题,问题大致(问题的链接为:http://social.msdn.microsoft.com/Forums/zh-CN/52e6 ...
- lua中易混淆函数
lua中易混淆的函数 ipairs和pairs: ipairs只能顺序遍历table,遇到key不是数字就会退出 pairs可以遍历table中所有元素 ----------------------- ...
- java多线程中的三种特性
java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...
- JavaScript中易混淆的DOM属性及方法对比
JavaScript中易混淆的DOM属性及方法对比 ParentNode.children VS Node.prototype.childNodes ParentNode.children:该属性继承 ...
随机推荐
- [Locked] Inorder Successor in BST
Inorder Successor in BST Given a binary search tree and a node in it, find the in-order successor of ...
- bzoj3669: [Noi2014]魔法森林 lct
记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸 然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以 ...
- WCF 项目应用连载[3] - 双向通信 实例管理与服务端监控
WCF 项目应用连载[1] - 索引 - 轻量级的Log系统 - Lig Sample -序 第二节我们已经创建了Lig项目,并且能稳定工作了.现在我们来改进ILigAgent接口,实现WCF的双向通 ...
- Android 更新UI的两个方法
Android 更新UI的两个方法 在Android的开发过程中,常常需要适时的更新UI.Androd中的UI是在主线程中更新的.如果在主线程之外的线程中直接更新,就会出现报错并抛出异常: andro ...
- android蓝牙4.0(BLE)开发之ibeacon初步
一个april beacon里携带的信息如下 ? 1 <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC ...
- Java对存储过程的调用方法 --转载
一.Java如何实现对存储过程的调用: A:不带输出参数的 create procedure getsum <--此处为参数--> as declare @sum int<--定义变 ...
- JDK5-注解
注解是一个类,一个声明就是一个对象 1. 简单注解 @SuppressWarnings("msg") - 压缩/抑制警告 @Deprecated - 声明过时 @Override ...
- Electron
跨平台桌面app开发 Appjs hex nwjs electron 官网:http://electron.atom.io/ 中文文档:https://github.com/atom/electron ...
- CSS对浏览器的兼容性常见处理方式小结
CSS技巧 1.div的垂直居中问题: vertical-align:middle; 将行距增加到和整个DIV一样高 line-height:200px; 然后插入文字,就垂直居中了. 缺点:要控制内 ...
- Dhroid框架笔记(IOC、EventBus)
dhroid 目前包含了6大组件供大家使用1.Ioc容器: (用过spring的都知道)视图注入,对象注入,接口注入,解决类依赖关系2.Eventbus: android平台事件总线框架,独创延时事件 ...