`

Java并发编程实践——线程安全

阅读更多

编写线程安全的代码的核心在于,对对象状态访问的控制与管理,特别对共享的、可变的状态。

 

一般地讲,一个对象的状态就是它所包含的数据,存储在状态变量中,比如实例域或静态域。一个对象的状态可能还来自于它所依赖的其他对象,比如HashMap的状态一部分是存储在自己的对象空间之中的,但另一部分存储在许多的Map.Entry对象之间。所以一个对象的状态是指那些可被外界访问的方法所影响(改变)的数据。

 

我们讨论的线程安全性好像是关于代码的,但是我们真正要做的,是在不可控制的并发访问中如何保护共享数据。

 

一个对象是否应该是线程安全的,这取决于它是否会被多个线程访问。

 

Java中首要的同步机制是synchronized关键字,它提供了独占锁。除此之外,还有volatile变量、显示锁(Lock)、原子变量的使用。

 

在没有正确同步的情况下,如果多个线程访问了同一个变量,你的程序就存在隐患,有3种方法来修复它:

1、不要跨线程共享变量;

2、如果确实要共享,则使状态变量不可变;或

3、只能在任何访问状态变量的时候使用同步。

 

设计线程安全的类时,有三种技术很好的做到安全:封装(即尽量降低域的可访问能力)、不可变、明确的规范。

 

无状态的对象永远是线程安全的。

 

Servlet是多线程共享的,所以我们在设计Servlet不要设计状态,否则要确保这些共享的状态域的线程安全。

 

i++,自增操作不是原子性的,它包括三个动作:获取当前值,加1,写回新值。

 

Atomic类型的变量只能保证变量本身一条语句的原子性,不能这个变量多条语句一起执行的原子性。

 

synchronized方法虽然解决了线程安全性问题,但同时可能带来线程性能上的问题。

 

synchronized所获取的锁与ReentrantLock锁都是可重入锁,重入锁的实现是通过为每个锁关联一个请求计数和一个占有它的线程。当计数为0时,认为锁是未被占有的。线程请求一个未被占有的锁时,JVM将记录锁的占有者,并具将请求计数器置为1。如果同一线程再次请求这个锁,计数将递增;每次占用线程退出同步块,计数器值将递减,直到计数器达到0,锁才被释放。

 

即然同步可以避免竞争条件,为什么不将每个方法都声明为synchronized类型?如同Vector一样,仅仅同步它每个方法,并不足以确保在Vector上执行的复合操作是原子的:

if(!vector.contains(element))

    vecotr.add(element);

虽然同步方法确保了不可分割操作的原子性,但是把多个操作整合到一个复合操作时,还是需要额外的锁。

 

锁定整个方法会导致弱并发的问题,并发性能会大大下降,幸运的是,我们可能通过缩小synchronized块的范围来维护线程安全性,很容易提升并发性。但你就应该谨慎地控制synchronized块不要过小,因你你不可以将一个原子操作分解到多个synchronized块中。不过你应该尽量从synchronized块中分离耗时的且不影响共享状态的操作。这样即使在耗时操作的执行过程中,也不会阻止其他线程访问共享状态。

 

请求与释放锁的操作需要开销,所以将synchronized埠分解得过于琐碎是不合理的。在分成多个同步块时要将耗时但又不影共享变量的操作放在同步块外调用,特别是要注意I/O与线程阻塞方法的调用,一般不要将其放在块里调用。

 

 

 

 

分享到:
评论
1 楼 yangguo 2010-12-29  
写得很深刻啊。

相关推荐

    Java全能学习面试手册——Java面试题库.zip

    80 并发编程面试专题.pdf 81 并发面试题.pdf 82 多线程,高并发.pdf 83 多线程面试59题(含答案)_.pdf 84 分布式缓存 Redis + Memcached 经典面试题!.pdf 85 搞定 HR 面试的 40 个必备问题!.pdf 86 集合框架.pdf ...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ │ 9.JAVA并发编程之多线程并发同步业务场景与解决方案.wmv │ │ │ ├─10.微服务架构之Spring Cloud Eureka 场景分析与实战 │ │ 10.微服务架构之Spring Cloud Eureka 场景分析与实战.wmv │ │ │ ├─11....

    大学生信息管理系统——初学路上自己摸索实践的项目.zip

    Java是一种高性能、跨平台的面向对象编程语言。它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势...

    2021最新java面试合集pdf.rar

    Java并发Fork-Join框架原理解析.docx JAVA核心知识整理.pdf JAVA核心知识点整理.pdf Java面试笔记.docx JAVA面试题解惑系列.pdf Java面试题(基础).pdf JVM 实用参数系列 - v1.0.pdf JVM与性能优化知识点整理.pdf ...

    Java毕业设计-JAVA局域网飞鸽传书软件设计与实现(源代码+论文).rar

    该软件的设计与实现涵盖了Java网络编程、图形用户界面设计、文件操作等多个方面,适合作为计算机专业学生的毕业设计或实践项目。 **核心功能**: 1. **用户注册与登录**:支持用户创建账户和登录系统,确保数据的...

    操作系统课程设计——模拟生产者与消费者(java)

    掌握线程创建和终止的方法,加深对线程和进程概念的理解,会用同步与互斥方法实现线程之间的进行操作。 在学习操作系统课程的基础上,通过实践加深对进程同步的认识,同时,可以提高运用操作系统知识解决实际问题的...

    asp.net知识库

    翻译MSDN文章 —— 泛型FAQ:最佳实践 Visual C# 3.0 新特性概览 C# 2.0会给我们带来什么 泛型技巧系列:如何提供类型参数之间的转换 C#2.0 - Object Pool 简单实现 Attributes in C# 手痒痒,也来个c# 2.0 object ...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    Java的产生与流行是当今Internet发展的客观要求,Java是一门各方面性能都很好的编程语言,它的基本特点是简单、面向对象、分布式、解释的、健壮的、安全的、结构中立的、可移植的、性能很优异的、多线程的、动态的,...

    基于J2EE框架的个人博客系统项目毕业设计论...

    Java的产生与流行是当今Internet发展的客观要求,Java是一门各方面性能都很好的编程语言,它的基本特点是简单、面向对象、分布式、解释的、健壮的、安全的、结构中立的、可移植的、性能很优异的、多线程的、动态的,...

    代码之美(中文完整版).pdf

    1.1 编程实践 1.2 实现 1.3 讨论 1.4 其他的方法 1.5 构建 1.6 小结 第2章 Subversion中的增量编辑器:像本体一样的接口 2.1 版本控制与目录树的转换 2.2 表达目录树的差异 2.3 增量编辑器接口 2.4 但这是不是艺术?...

Global site tag (gtag.js) - Google Analytics