博客
关于我
【Java并发编程实战】02线程安全性
阅读量:540 次
发布时间:2019-03-09

本文共 1757 字,大约阅读时间需要 5 分钟。

什么是线程安全性

当多个线程访问某个类时,如果不管线程调用的方式或执行顺序,并且主调代码中不需要额外的同步或协同,类能够正确运行,那么这个类就是线程安全的。无状态对象天然就是线程安全的,例如Servlet。

原子性

线程安全的核心需求之一是原子性。

竞争条件

竞争条件是由于不恰当的执行顺序导致不正确结果的情形。 例如,“先检查后执行”的操作,比如延迟初始化: ```javaif(instance == null) { instance = new SomeObject();}```此外,“读取-修改-写入”操作可能导致竞争条件,因为结果依赖于状态,例如递增运算: ```javalong count = 0;count++;```

复合操作

复合操作是指一组互为原子操作的操作集合。为了确保线程安全性,需要将所有涉及同一状态的操作进行原子处理。例如,使用`AtomicLong`来保证递增运算的原子性: ```javaAtomicLong count = new AtomicLong(0);count.incrementAndGet();```

加锁机制

在Java中,通过加锁的方式来维护线程安全性。内置锁是实现这一目的的核心工具。

内置锁

通过`syncronized`关键字修饰的方法或代码块实现原子操作。例如,最简单的`syncronized`方法: ```javapublic synchronized void doSomeWork() { // ...}``` 其中,`syncronized`表示方法内部的代码块是原子操作,整个方法会自动协调线程进入该代码块。

可重入锁

内置锁是可重入的,这意味着同一线程可以多次获得同一锁。这种粒度的锁设计使并发编程更加简便。例如: ```javapublic class LoggingWidget extends Widget { public synchronized void doSomething() { super.doSomething(); // 可重入防止死锁 }}```

用锁保护可变的状态

对于共享多个线程访问的可变状态变量,需要在所有访问代码块中都持有同一个锁,以确保数据的一致性。例如:

活跃性与性能考量

粗粒度的锁会导致活跃性问题,但细化锁的使用可以平衡安全性与性能。例如,在改进后的 Servlet 规划中移除不必要的同步,仅对关键状态进行保护:
public class CachedFactorizer implements Servlet {    @GuardedBy("this") private BigInteger lastNumber;    @GuardedBy("this") private BigInteger[] lastFactors;    public void service(ServletRequest req, ServletResponse resp) {        BigInteger i = extractFromRequest(req);        BigInteger[] factors = null;                synchronized (this) {            if (i.equals(lastNumber)) {                factors = lastFactors.clone();            }        }                if (factors == null) {            synchronized (this) {                lastNumber = i;                lastFactors = factors.clone();            }        }                encodeIntoResponse(resp, factors);    }}

通过这种方式,可以最大限度地减少锁等时间,同时仍然保证线程安全性。这是优化并发 Servlet 编程中的常见方法。

转载地址:http://waisz.baihongyu.com/

你可能感兴趣的文章
C++学习日记2——多态篇的纯虚函数和抽象类
查看>>
F - 数据结构实验之链表四:有序链表的归并
查看>>
为什么使用%lf读取double型的值,而用%f进行显示?
查看>>
用JavaScript实现希尔排序
查看>>
iconfont字体图标导入到vue项目中
查看>>
2020.11.30-12.6周报
查看>>
Nuxt.js服务器端渲染框架
查看>>
Svn commit failed aborting commit
查看>>
卧槽!细说JVM内存模型,已拿到offer
查看>>
带你一起手撕Dubbo,SpringBoot与Cloud,深入剖析
查看>>
dynamo中如何通过节点读取cad图纸数据
查看>>
纯干货!深度分析一下AQS原理,一文全懂
查看>>
腾讯Java面试题,从基础到源码统统帮你搞定,2年以上经验必看
查看>>
字节跳动算法工程师总结:腾讯+字节+阿里面经真题汇总,含面试题+答案
查看>>
(二)MyBatis学习笔记——使用映射配置文件进行CRUD、核心配置文件使用
查看>>
LeetCode 76. 最小覆盖子串
查看>>
shell基础 - 03
查看>>
第七课时logback日志框架介绍及应用
查看>>
第十一课时通讯录列表前后端调用
查看>>
java注解完整实例
查看>>