`

并发编程(二)------写线程安全的Java代码

    博客分类:
  • JAVA
 
阅读更多

在写Java程序的时候,何时需要进行并发控制,关键在于判断这段程序或这个类是否是线程安全的。

当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步,这个类的行为仍然是正确的,那么称这个类是线程安全的。我们设计类就是要在有潜在并发问题存在情况下,设计线程安全的类。线程安全的类可以通过以下手段来满足:

  • 不跨线程共享变量
  • 使状态变量为不可变的
  • 在任何访问状态变量的时候使用同步。
  • 每个共享的可变变量都需要由唯一一个确定的锁保护。

满足线程安全的一些思路

1)从源头避免并发问题

很多开发者一想到有并发的可能就通过底层技术来解决问题,其实往往可以通过上层的架构设计和业务分析来避免并发场景。比如我们需要用多线程或分布式 集群来计算一堆客户的相关统计值,由于客户的统计值是共享数据,因此会有并发潜在可能。但从业务上我们可以分析出客户与客户之间数据是不共享的,因此可以 设计一个规则来保证一个客户的计算工作和数据访问只会被一个线程或一台工作机完成,而不是把一个客户的计算工作分配给多个线程去完成。这种规则很容易设 计。当你从源头就避免了并发问题的可能,下面的工作就完全可以不用担心线程安全问题。

2)无状态就是线程安全

多线程编程或者分布式编程最忌讳有状态,一有状态就不但限制了其横向扩展能力,也是产生并发问题的起源。当你设计的类是无状态的,那么它永远都是线程安全的。因此在设计阶段需要考虑如何用无状态的类来满足你的业务需求

3)分清原子性操作和复合操作

所谓原子性,是说一个操作不会被其他线程打断,能保证其从开始到结束独享资源连续执行完这一操作。如果所有程序块都是原子性的,那么就不存在任何并 发问题。而很多看上去像是原子性的操作正式并发问题高灾区。比如所熟知的计数器(count++)和check-then-act,这些都是很容易被忽视 的,例如大家所常用的惰性初始化模式,以下代码就不是线程安全的:

  1. @NotThreadSafe  
  2. public class LazyInitRace {  
  3.     private ExpensiveObject instance = null;  
  4.     public ExpensiveObject getInstance() {  
  5.         if (instance == null)  
  6.             instance = new ExpensiveObject();  
  7.         return instance;  
  8.     }  
  9. }  

这段代码具体问题在于没有认识到if(instance==null)和instance = new ExpensiveObject();是两条语句,放在一起就不是原子性的,就有可能当一个线程执行完if(instance==null)后会被中断, 另一个线程也去执行if(instance==null),这次两个线程都会执行后面的instance = new ExpensiveObject();这也是这个程序所不希望发生的。

虽然check-then-act从表面上看很简单,但却普遍存在与我们日常的开发中,特别是在数据库存取这一块。比如我们需要在数据库里存一个客 户的统计值,当统计值不存在时初始化,当存在时就去更新。如果不把这组逻辑设计为原子性的就很有可能产生出两条这个客户的统计值。

在单机环境下处理这个问题还算容易,通过锁或者同步来把这组复合操作变为原子操作,但在分布式环境下就不适用了。一般情况下是通过在数据库端做文章,比如通过唯一性索引或者悲观锁来保障其数据一致性。当然任何方案都是有代价的,这就需要具体情况下来权衡。

另外,java1.5以后提供了一套提供原子性操作的类,有兴趣的可以研究一下它是如何在软件层面保证原子性的。

4)锁的合理使用

大家都知道可以用锁来解决并发问题,但在具体使用上还有很多讲究,比如:

  • 每个共享的可变变量都需要由一个个确定的锁保护。
  • 一旦使用了锁,就意味着这段代码的执行就丧失了操作系统多道程序的特性,会在一定程度上影响性能
  • 锁不能解决在分布式环境共享变量的并发问题
 
 
分享到:
评论

相关推荐

    JAVA并发编程实践-中文-高清-带书签-完整版

    最后,本书还涵盖了Java并发编程的最新发展,如Fork/Join框架和Parallel Streams,这些是Java 7及以后版本引入的新特性,能够帮助开发者充分利用多核处理器的优势,编写出高性能的并行代码。 总而言之,《JAVA并发...

    Java 并发编程实战-随书源码

    10. **jcip-examples-src**:这个子文件夹可能包含了《Java并发编程实战》书中提到的各种示例代码,涵盖了上述知识点的实践应用。 通过学习和实践这些内容,开发者可以更好地理解和掌握Java并发编程,从而编写出...

    java并发编程2

    以上知识点覆盖了Java并发编程的主要方面,包括线程管理、同步机制、并发工具、设计模式、并发集合以及并发编程的最佳实践等,是理解和掌握Java并发编程的关键。在实际开发中,理解和熟练运用这些知识可以编写出高效...

    Java并发编程-3.pdf

    Java并发编程中的多线程协作机制 在 Java 并发编程中,多线程协作机制是非常重要的一部分。多线程协作机制是指在多线程编程中,多个线程之间如何协作、同步和通信,以达到共同完成某个任务的目的。Java 提供了多种...

    JAVA并发编程艺术pdf版

    《JAVA并发编程艺术》是Java开发者深入理解和掌握并发编程的一本重要著作,它涵盖了Java并发领域的核心概念和技术。这本书详细阐述了如何在多线程环境下有效地编写高效、可靠的代码,对于提升Java程序员的技能水平...

    Java 并发编程实战.pdf

    书中会首先介绍Java并发编程的基础知识,包括线程的创建和运行,同步机制的基本用法,以及Java内存模型的相关概念。随着章节的深入,作者可能会更深入地讲解Java提供的并发工具,例如锁、原子变量、线程池、以及并发...

    Java并发编程实战-高清完整版-带书签

    书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及验证线程安全的规则,如何将小的线程安全类组合成更大的线程安全类,如何利用线程来提高...

    java并发编程实践pdf笔记

    Java并发编程实践是Java开发中不可或缺的一个领域,它涉及到如何高效、正确地处理多线程环境中的任务。这本书的读书笔记涵盖了多个关键知识点,旨在帮助读者深入理解Java并发编程的核心概念。 1. **线程和进程的...

    Java并发编程实践-电子书-04章

    ### Java并发编程实践-电子书-04章:利用Amino构建高效并发应用程序 #### 开源软件Amino:并发编程的利器 Amino是一款由Apache支持的开源软件,专为解决Java多线程环境中常见的并发问题而设计。通过提供一系列高...

    Java并发编程实践高清pdf及源码

    《Java并发编程实践》是一本深入探讨Java多线程编程的经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和David Holmes等专家共同编写。这本书全面介绍了Java平台上的并发编程技术,是Java开发...

    Java并发编程-线程安全与基础构建模块

    本文将深入探讨"Java并发编程-线程安全与基础构建模块"这一主题,旨在帮助开发者理解如何有效地处理并发问题,提高程序性能和稳定性。 首先,线程安全是并发编程中的核心概念,指的是多个线程访问同一资源时,无论...

    Java并发编程--BlockingQueue.docx

    总之, BlockingQueue 是 Java 并发编程中不可或缺的一部分,它简化了多线程间的数据交换,保证了线程安全,提高了程序的并发性能。开发者可以根据实际需求选择不同类型的阻塞队列实现,以适应不同的并发场景。

    java并发编程1-9章

    《Java并发编程1-9章》是一份涵盖了Java并发编程核心...通过学习这些章节,Java开发者可以提升在并发编程领域的专业技能,更好地应对复杂的并发场景,优化程序性能,减少潜在的线程安全问题,从而提升整体系统质量。

    java 并发编程的艺术pdf清晰完整版 源码

    9. **并发编程最佳实践**:最后,书中会提供一些并发编程的最佳实践,帮助读者避免常见的并发陷阱,写出更健壮、更高效的代码。 通过阅读《Java并发编程的艺术》这本书,开发者不仅可以掌握Java并发编程的基础知识...

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第一阶段28讲、线程生产者消费者的综合实战结合Java8语法.mp4 │ 高并发编程第一阶段29讲、如何实现一个自己的显式锁Lock精讲上.mp4 │ 高并发编程第一阶段30讲、如何实现一个自己的显式锁Lock精讲...

Global site tag (gtag.js) - Google Analytics