编写线程安全的代码的核心在于,对对象状态访问的控制与管理,特别对共享的、可变的状态。
一般地讲,一个对象的状态就是它所包含的数据,存储在状态变量中,比如实例域或静态域。一个对象的状态可能还来自于它所依赖的其他对象,比如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与线程阻塞方法的调用,一般不要将其放在块里调用。
分享到:
相关推荐
Java并发编程是一个复杂而重要的主题,它涉及到多线程、同步机制、线程池和并发容器等关键概念。Amino框架是Java并发编程领域的一个工具,它旨在简化并发编程,提高程序的性能和可维护性。这篇博客文章可能详细探讨...
本篇文章将深入探讨Java并发编程的相关知识点,主要基于提供的两个文件——"Java并发编程实战(中文版).pdf"和"Java Concurrency in Practice.pdf"。 1. **线程与并发** - **线程基础**:Java中的线程是并发执行...
《JAVA并发编程实践》是一本深入探讨Java多线程编程技术的专业书籍,旨在帮助开发者理解和掌握在Java平台上进行高效并发编程的关键知识。本书涵盖了从基本概念到高级特性的全面内容,是Java程序员进阶的必读之作。 ...
《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。它涵盖了从基础到高级的并发编程概念,旨在帮助读者提升在多线程环境下的编程能力,优化系统性能,避免并发问题。以下是对该书内容的详细...
《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。并发编程是现代软件开发中的核心技能之一,尤其是在多核处理器普及的今天,利用并发能够显著提升程序的执行效率和响应速度。以下是对该书...
为了确保线程安全,开发者需要深入理解Java的并发控制机制,合理使用同步策略,如使用`synchronized`关键字、`Lock`接口以及原子操作类等。 #### 结论 Java线程是Java编程中一个强大且必要的特性,它极大地扩展了...
这本书是Java并发编程的实践指南,适合有一定并发经验的开发者。它更注重于实际应用和最佳实践,内容包括: - **并发模式**:介绍了如Producer-Consumer、Builder、Guarded Suspension等经典并发模式,并提供了...
首先,我们需要理解Java并发编程的基础——线程。在Java中,通过`Thread`类或者实现`Runnable`接口来创建线程。线程是程序执行的最小单位,允许多个任务在同一时间内执行。通过线程,我们可以实现并行处理,提升程序...
在Java编程中,多线程是处理并发执行的关键技术,它允许程序同时执行多个任务,提高了系统的效率和响应性。本资料主要探讨了Java中的并发模式和特性,...通过不断实践和学习,可以在Java并发编程领域达到更高的水平。
首先,我们要理解Java并发编程的基础——线程。线程是程序执行的最小单元,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈等,而共享堆内存。在多核处理器系统中,多个线程可以同时运行,提升程序执行效率。 ...
### Java并发编程实践——第5章 数据冲突及诊断工具MTRAT #### 5.1 如何避免数据冲突 在并发编程中,数据冲突是指多个线程对同一资源的访问而导致的问题,这些问题可能会破坏程序的一致性和正确性。为了避免数据...
为了更好地理解Java并发编程的实际应用,我们可以考虑一个简单的例子——使用`Future`和`Callable`来实现异步任务的执行。假设有一个复杂的计算任务需要长时间执行,但主程序不能等待这个任务完成。此时,可以将计算...
7. **Java并发编程的最佳实践** - **线程安全的设计模式**:如单例模式的线程安全实现、双重检查锁定等。 - **并发编程原则**:避免阻塞、减少锁的使用、使用并发集合等。 8. **Java内存模型(JMM)** - **JMM的...
### Java高并发编程实践技巧 #### 1. volatile关键字 `volatile`关键字用于修饰变量,保证了该变量对所有线程的可见性。当一个线程修改了这个变量的值,新值对于其他线程来说是立即可见的。 #### 2. 使用...
《Java并发编程实战》是Java开发者深入理解和掌握并发编程的一本经典著作。这本书全面地介绍了如何在Java平台上高效、安全地编写多线程程序,帮助读者理解并解决并发编程中的各种挑战。 首先,我们需要理解“并发”...
在IT行业中,多线程和线程安全是Java编程中不可或缺的重要概念,特别是在处理大量并发操作或者实现高效网络服务时。...对于希望深入学习Java并发编程和网络编程的开发者来说,这是一个非常有价值的参考资料。