9、Java并发性和多线程-线程安全与共享资源
以下内容转自http://ifeve.com/thread-safety/:
允许被多个线程同时执行的代码称作线程安全的代码。线程安全的代码不包含竞态条件。当多个线程同时更新共享资源时会引发竞态条件。因此,了解Java线程执行时共享了什么资源很重要。
局部变量
局部变量存储在线程自己的栈中。也就是说,局部变量永远也不会被多个线程共享。所以,基础类型的局部变量是线程安全的。下面是基础类型的局部变量的一个例子:
- public void someMethod(){
- long threadSafeInt = 0;
- threadSafeInt++;
- }
局部的对象引用
对象的局部引用和基础类型的局部变量不太一样。尽管引用本身没有被共享,但引用所指的对象并没有存储在线程的栈内。所有的对象都存在共享堆中。如果在某个方法中创建的对象不会逃逸出(译者注:即该对象不会被其它方法获得,也不会被非局部变量引用到)该方法,那么它就是线程安全的。实际上,哪怕将这个对象作为参数传给其它方法,只要别的线程获取不到这个对象,那它仍是线程安全的。下面是一个线程安全的局部引用样例:
- public void someMethod(){
- LocalObject localObject = new LocalObject();
- localObject.callMethod();
- method2(localObject);
- }
- public void method2(LocalObject localObject){
- localObject.setValue("value");
- }
样例中LocalObject对象没有被方法返回,也没有被传递给someMethod()方法外的对象。每个执行someMethod()的线程都会创建自己的LocalObject对象,并赋值给localObject引用。因此,这里的LocalObject是线程安全的。事实上,整个someMethod()都是线程安全的。即使将LocalObject作为参数传给同一个类的其它方法或其它类的方法时,它仍然是线程安全的。当然,如果LocalObject通过某些方法被传给了别的线程,那它就不再是线程安全的了。
对象成员
对象成员存储在堆上。如果两个线程同时更新同一个对象的同一个成员,那这个代码就不是线程安全的。下面是一个样例:
- public class NotThreadSafe{
- StringBuilder builder = new StringBuilder();
- public add(String text){
- this.builder.append(text);
- }
- }
如果两个线程同时调用同一个NotThreadSafe
实例上的add()方法,就会有竞态条件问题。例如:
- NotThreadSafe sharedInstance = new NotThreadSafe();
- new Thread(new MyRunnable(sharedInstance)).start();
- new Thread(new MyRunnable(sharedInstance)).start();
- public class MyRunnable implements Runnable{
- NotThreadSafe instance = null;
- public MyRunnable(NotThreadSafe instance){
- this.instance = instance;
- }
- public void run(){
- this.instance.add("some text");
- }
- }
注意两个MyRunnable共享了同一个NotThreadSafe对象。因此,当它们调用add()方法时会造成竞态条件。
当然,如果这两个线程在不同的NotThreadSafe实例上调用call()方法,就不会导致竞态条件。下面是稍微修改后的例子:
- new Thread(new MyRunnable(new NotThreadSafe())).start();
- new Thread(new MyRunnable(new NotThreadSafe())).start();
现在两个线程都有自己单独的NotThreadSafe对象,调用add()方法时就会互不干扰,再也不会有竞态条件问题了。所以非线程安全的对象仍可以通过某种方式来消除竞态条件。
线程控制逃逸规则
线程控制逃逸规则可以帮助你判断代码中对某些资源的访问是否是线程安全的。
- 如果一个资源的创建,使用,销毁都在同一个线程内完成,
- 且永远不会脱离该线程的控制,则该资源的使用就是线程安全的。
资源可以是对象,数组,文件,数据库连接,套接字等等。Java中你无需主动销毁对象,所以“销毁”指不再有引用指向对象。
即使对象本身线程安全,但如果该对象中包含其他资源(文件,数据库连接),整个应用也许就不再是线程安全的了。比如2个线程都创建了各自的数据库连接,每个连接自身是线程安全的,但它们所连接到的同一个数据库也许不是线程安全的。比如,2个线程执行如下代码:
- 检查记录X是否存在,如果不存在,插入X
如果两个线程同时执行,而且碰巧检查的是同一个记录,那么两个线程最终可能都插入了记录:
- 线程1检查记录X是否存在。检查结果:不存在
- 线程2检查记录X是否存在。检查结果:不存在
- 线程1插入记录X
- 线程2插入记录X
同样的问题也会发生在文件或其他共享资源上。因此,区分某个线程控制的对象是资源本身,还是仅仅到某个资源的引用很重要。
9、Java并发性和多线程-线程安全与共享资源的更多相关文章
- 15、Java并发性和多线程-线程通讯
以下内容转自http://ifeve.com/thread-signaling/: 线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 例如,线程B可以等待线程 ...
- 10、Java并发性和多线程-线程安全与不可变性
以下内容转自http://ifeve.com/thread-safety-and-immutability/: 当多个线程同时访问同一个资源,并且其中的一个或者多个线程对这个资源进行了写操作,才会产生 ...
- 26、Java并发性和多线程-线程池
以下内容转自http://ifeve.com/thread-pools/: 线程池(Thread Pool)对于限制应用程序中同一时刻运行的线程数很有用.因为每启动一个新线程都会有相应的性能开销,每个 ...
- java 并发性和多线程 -- 读感 (一 线程的基本概念部分)
1.目录略览 线程的基本概念:介绍线程的优点,代价,并发编程的模型.如何创建运行java 线程. 线程间通讯的机制:竞态条件与临界区,线程安全和共享资源与不可变性.java内存模型 ...
- Java 并发和多线程(一) Java并发性和多线程介绍[转]
作者:Jakob Jenkov 译者:Simon-SZ 校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...
- Java并发性和多线程
Java并发性和多线程介绍 java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题, ...
- Java并发性和多线程介绍
java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题,多开线程就好: 快速响应,异步式 ...
- Java高级教程:Java并发性和多线程
Java并发性和多线程: (中文,属于人工翻译,高质量):http://ifeve.com/java-concurrency-thread-directory/ (英文):http://tutoria ...
- java 并发性和多线程 -- 读感 (二 线程间通讯,共享内存的机制)
参考文章:http://ifeve.com/java-concurrency-thread-directory/ 其中的竞态,线程安全,内存模型,线程间的通信,java ThreadLocal类小节部 ...
随机推荐
- DFS HDU 5305 Friends
题目传送门 /* 题意:每个点都要有偶数条边,且边染色成相同的两部分,问能有多少种染色方法 DFS+剪枝:按照边数来DFS,每种染色数为该点入度的一半,还有如果点不是偶数边就不DFS 这是别人的DFS ...
- 最短路 Codeforces Round #103 (Div. 2) D. Missile Silos
题目传送门 /* 最短路: 不仅扫描边,还要扫描点:点有两种情况,一种刚好在中点,即从u,v都一样,那么最后/2 还有一种是从u,v不一样,两种的距离都是l 模板错了,逗了好久:( */ #inclu ...
- C - GCD LCM
Description The GCD of two positive integers is the largest integer that divides both the integers w ...
- Matlab vs Python 作图
-- Matlab 作图示例 x=-3:0.00003:3; y1=sin(x)./x; y2=x./sin(x); plot(x,y1,x,y2); -- Python 作图示例 import nu ...
- 237 Delete Node in a Linked List 删除链表的结点
编写一个函数,在给定单链表一个结点(非尾结点)的情况下,删除该结点. 假设该链表为1 -> 2 -> 3 -> 4 并且给定你链表中第三个值为3的节点,在调用你的函数后,该链表应变为 ...
- 常用的几个Dos命令-持续更新中
1.服务相关 (1).查看服务 C:\Windows\system32>net start 已经启动以下 Windows 服务: (2).启动服务 C:\Windows\system32> ...
- 【hive】hive表很大的时候查询报错问题
线上hive使用环境出现了一个奇怪的问题,跑一段时间就报如下错误: FAILED: SemanticException MetaException(message:Exception thrown w ...
- bash 博弈
转载并修改自: http://www.cnblogs.com/wulangzhou/archive/2013/03/14/2959660.html 简单的取拿游戏一堆石子(或者其它的什么东西),下面是 ...
- css中常见几种float方式以及倒计时(刷新页面不清)
css中常见几种float方式 http://jingyan.baidu.com/article/72ee561a670269e16138dfd5.html <script type=" ...
- Windows下80端口被进程System&PID=4占用的解决方法
我的占用原因是 SQL Server Reporting Services,停止掉这个服务并设置其为手动启动即可 如果你并没有安装 SQL Server,请参考下文解决 =============== ...