在写Java程序的时候,何时需要进行并发控制,关键在于判断这段程序或这个类是否是线程安全的。
当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步,这个类的行为仍然是正确的,那么称这个类是线程安全的。我们设计类就是要在有潜在并发问题存在情况下,设计线程安全的类。线程安全的类可以通过以下手段来满足:
- 不跨线程共享变量
- 使状态变量为不可变的
- 在任何访问状态变量的时候使用同步。
- 每个共享的可变变量都需要由唯一一个确定的锁保护。
满足线程安全的一些思路
1)从源头避免并发问题
很多开发者一想到有并发的可能就通过底层技术来解决问题,其实往往可以通过上层的架构设计和业务分析来避免并发场景。比如我们需要用多线程或分布式集群来计算一堆客户的相关统计值,由于客户的统计值是共享数据,因此会有并发潜在可能。但从业务上我们可以分析出客户与客户之间数据是不共享的,因此可以设计一个规则来保证一个客户的计算工作和数据访问只会被一个线程或一台工作机完成,而不是把一个客户的计算工作分配给多个线程去完成。这种规则很容易设计。当你从源头就避免了并发问题的可能,下面的工作就完全可以不用担心线程安全问题。
2)无状态就是线程安全
多线程编程或者分布式编程最忌讳有状态,一有状态就不但限制了其横向扩展能力,也是产生并发问题的起源。当你设计的类是无状态的,那么它永远都是线程安全的。因此在设计阶段需要考虑如何用无状态的类来满足你的业务需求
3)分清原子性操作和复合操作
所谓原子性,是说一个操作不会被其他线程打断,能保证其从开始到结束独享资源连续执行完这一操作。如果所有程序块都是原子性的,那么就不存在任何并发问题。而很多看上去像是原子性的操作正式并发问题高灾区。比如所熟知的计数器(count++)和check-then-act,这些都是很容易被忽视的,例如大家所常用的惰性初始化模式,以下代码就不是线程安全的:
这段代码具体问题在于没有认识到if(instance==null)和instance = new ExpensiveObject();是两条语句,放在一起就不是原子性的,就有可能当一个线程执行完if(instance==null)后会被中断,另一个线程也去执行if(instance==null),这次两个线程都会执行后面的instance = new ExpensiveObject();这也是这个程序所不希望发生的。
虽然check-then-act从表面上看很简单,但却普遍存在与我们日常的开发中,特别是在数据库存取这一块。比如我们需要在数据库里存一个客户的统计值,当统计值不存在时初始化,当存在时就去更新。如果不把这组逻辑设计为原子性的就很有可能产生出两条这个客户的统计值。
在单机环境下处理这个问题还算容易,通过锁或者同步来把这组复合操作变为原子操作,但在分布式环境下就不适用了。一般情况下是通过在数据库端做文章,比如通过唯一性索引或者悲观锁来保障其数据一致性。当然任何方案都是有代价的,这就需要具体情况下来权衡。
另外,java1.5以后提供了一套提供原子性操作的类,有兴趣的可以研究一下它是如何在软件层面保证原子性的。
4)锁的合理使用
大家都知道可以用锁来解决并发问题,但在具体使用上还有很多讲究,比如:
- 每个共享的可变变量都需要由一个个确定的锁保护。
- 一旦使用了锁,就意味着这段代码的执行就丧失了操作系统多道程序的特性,会在一定程度上影响性能
- 锁不能解决在分布式环境共享变量的并发问题
分享到:
相关推荐
Java编程基础教程 Java是一种广泛使用的面向对象的...随着技能的提升,你可以进一步探索更高级的主题,如设计模式、并发编程、框架(Spring、Hibernate等)以及Java EE(企业级应用)。祝你在Java学习之路上一帆风顺!
在“语言技术Java:二(进阶)”这个学习资源中,我们主要会深入探讨Java编程语言的高级概念和技巧。这个资源由台湾的良葛格慷慨分享,旨在帮助初学者进一步提升Java技能,且所有资料以网页形式呈现,使得学习资料更加...
理解线程的生命周期、同步机制(如synchronized关键字、wait()、notify()方法)以及死锁问题,有助于编写高效、安全的并发代码。 在自考Java的过程中,熟悉标准库API,如IO流、集合、网络编程等模块,是非常必要的...
《实战Java高并发程序设计》第二版是一本深入探讨Java多线程和并发编程的书籍。这本书涵盖了Java并发编程的核心概念和技术,旨在帮助开发者在实际项目中高效地处理高并发场景。随书附带的代码提供了丰富的示例,以便...
6. **chap6.pdf** - 多线程编程是Java的一个重要方面,这一章可能会讲解线程的创建、同步、并发控制,以及线程池的使用。 7. **chap7.pdf** - 文件和I/O操作是任何编程语言的基础,这一章可能详细解释Java中的文件...
#### 四、面向对象编程(OOP) - **封装**: - 将数据和操作数据的方法绑定在一起,隐藏实现细节。 - 使用访问修饰符(public/private/protected)来限制对类成员的访问。 - **继承**: - 子类继承父类的属性和方法。 ...
《Head First Java》是入门学习Java编程的一本经典教材,以其独特的视觉设计和易于理解的教学方式深受初学者喜爱。第二版全面更新了内容,涵盖了...记得在实践中不断思考和探索,这样你的Java编程技能将得到显著提升。
《Codeeval Solutions in Java:深度探索编程挑战与实践》 在编程领域,解决挑战和问题是一种提升技能的有效方式。Codeeval平台提供了丰富的编程任务,旨在帮助开发者锻炼和提高其编程能力。本项目“codeeval-...
Java是一种广泛使用的面向...随着经验的积累,可以进一步探索高级主题,如设计模式、并发编程、Java EE框架等。记得实践是检验真理的唯一标准,理论结合实际项目会加快你的学习进度。祝你在Java的学习道路上一帆风顺!
- **多线程**:实现并发编程,提高程序的效率和响应速度。 - **网络编程**:客户端/服务器架构,包括TCP/IP和UDP协议的使用。 - **图形与图像处理**:利用Java的图形库绘制图形和处理图像。 - **JDBC**:Java与...
4. 异步编程与并发:Java提供了线程和并发工具,如ExecutorService、Semaphore等,帮助开发者编写高效且线程安全的代码。 四、Java I/O与网络编程 1. 输入/输出流:Java的I/O系统基于流,涵盖了文件操作、网络通信...
3. 并发编程:掌握Java并发API,如线程、同步机制、并发集合等,以及如何编写高效、安全的多线程程序。 六、实战应用 通过实例项目,将所学的敏捷开发原则与Java编程技术结合,体验真实的敏捷开发过程,提升问题...
### Java初级知识要点详解 #### 一、Java概述与基础知识 **1....** 编程是指通过编写计算机程序来实现...`StringBuffer`和`StringBuilder`都是用于操作字符串的类,其中`StringBuilder`在非线程安全的环境中效率更高。 ...
Java的核心是面向对象编程(OOP),主要体现在封装、继承和多态三个特性。 2.1 封装 封装是隐藏对象内部细节的过程,通过提供公共接口来访问私有数据。访问修饰符如`private`, `public`, `protected`实现这一目的。...
**JAVA基础PPT知识点概述** Java是一种广泛使用的高级编程语言,以其“一次编写,到处运行”的...随着学习的深入,你可以进一步探索Java的高级特性,如Lambda表达式、模块化系统、流API等,从而成为熟练的Java开发者。
《Java基础教程——phase1-java-...以上便是“phase1-java-fundamentals-02-12-2021”教程中涉及的Java基础知识,通过深入学习和实践,你将具备扎实的Java编程基础,为进一步探索更高级的Java技术铺平道路。
协程是Kotlin中用于处理并发编程的一种机制,它可以简化异步编程模型,避免回调地狱。 - **挂起函数**:在协程中可以挂起执行的函数。 - **异步编程**:使用协程来编写异步代码。 #### 十、Kotlin与Java互操作 ...
- **多线程编程**:了解Linux内核如何支持多线程环境下的并发操作。 - **设备驱动开发**:探索如何编写驱动程序,使内核能够支持不同的硬件设备。 - **安全机制**:研究内核中的安全特性,如SELinux、AppArmor等,以...