线程安全与共享资源
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
同样的问题也会发生在文件或其他共享资源上。因此,区分某个线程控制的对象是资源本身,还是仅仅到某个资源的引用很重要
文章转自 并发编程网-ifeve.com
多线程编程之线程的同步机制(下): Synchronized同步代码块 上一篇文章讲了多线程编程中Synchronized同步方法的相关内容,Synchronized除了同步方法之外还可以同步语句块,这篇文章就介绍Synchronized如何同步语句块。
相关文章
- 自定义Dictionary支持线程安全
- PHP常见安全问题及解决方法
- day02-多线程之线程安全
- 什么是线程安全
- 1-5-10 快恢在数字化安全生产平台 DPS 中的设计与落地
- java多线程 --ConcurrentLinkedQueue 非阻塞 线程安全队列
- HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么
- java多线程 --ConcurrentLinkedQueue 非阻塞 线程安全队列
- 阿里云安全基线 记录如下 不定时更新
- 一道面试题:StringBuffer a=new StringBuffer ("A"); StringBuffer b=new StringBuffer (StringBuffer线程安全 StringBuilder线程不安全)
- 阿里安全峰会:云安全的未来是什么样子的?
- Qt如何保证类的线程安全?(让多线程不再崩渍)
- Qt进程和线程之三:线程同步、可重入与线程安全
- 面对 Log4j2 漏洞,安全人都做了什么?
- GaussDB拿下的安全认证CC EAL4+究竟有多难?
- 【高并发】面试官问我:为什么局部变量是线程安全的?
- 60.第十四章 加密和安全 -- 安全机制(一)
- 《Java并发编程实战》第二章 线程安全 札记
- SASE——安全访问服务边缘,就是零信任接入服务
- JAVA中的线程安全与非线程安全
- Java中保证线程安全的三板斧
- 支持DevOps和功能安全/信息安全的静态代码分析器 Klocwork——Klocwork的主要功能特性:基于SAST(静态应⽤程序安全测试)查找安全漏洞;支持DevOps;⽀持⾏业标准要求的编码规范
- 如何使用安全代码防止网络安全威胁