在写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多线程和并发编程的书籍。这本书涵盖了Java并发编程的核心概念和技术,旨在帮助开发者在实际项目中高效地处理高并发场景。随书附带的代码提供了丰富的示例,以便...
Java并发编程是Java开发中的重要领域,特别是在大型分布式系统、多线程应用和服务器端程序设计中不可或缺。这个资源包“Java并发编程从入门到精通源码.rar”显然是为了帮助开发者深入理解并掌握这一关键技能。它包含...
这本书全面覆盖了Java并发编程的基础知识、核心概念以及高级技巧,旨在帮助读者理解如何在多线程环境中编写高效、安全的代码。 并发编程是现代软件开发中的重要组成部分,尤其是在服务器端和分布式系统中,它能够...
"并发编程Java代码示例.zip"这个压缩包很可能是包含了一系列有关Java并发编程的实例代码,帮助开发者理解和掌握如何在Java中有效地管理多线程。 Java并发编程涉及到的关键概念和知识点包括: 1. **线程**:线程是...
将其转换为Java代码时,可以写成: ```java public static int addOne(int x) { return x + 1; } ``` 需要注意的是,尽管这个例子非常简单,但在实际应用中,涉及到复杂的类型转换、函数式编程特性的映射等问题时...
《JAVA并发编程实践》这本书深入探讨了Java平台上的并发编程技术。并发编程是现代软件开发中的重要组成部分,尤其是在多核处理器越来越普及的今天,利用并发能够显著提高程序的执行效率和响应速度。以下是对该主题的...
- **示例代码:** 书中提供了大量的示例代码,涵盖各种并发编程的典型应用场景,帮助读者更好地理解并发编程的技术细节。 - **案例分析:** 分析真实世界中的并发编程问题,展示如何运用理论知识解决实际问题。 - **...
13. **并发编程**:Java提供了高级并发API,如ExecutorService、Future、Callable,以及并发集合如ConcurrentHashMap和CopyOnWriteArrayList,用于高效地管理多线程环境中的任务。 14. **JVM优化**:理解JVM的工作...
4. **进阶技术**:了解设计模式、JVM调优、Java并发编程、网络编程和数据库连接(JDBC)等。 5. **框架与工具**:熟悉常用的Java框架如Spring、Hibernate和MyBatis,以及开发工具如Eclipse、IntelliJ IDEA等。 #### ...
Java的口号是“Write Once, Run Anywhere”(一次编写,到处运行),意味着编写的Java代码可以在任何支持Java虚拟机(JVM)的平台上运行,而无需进行任何修改。 Java的主要特点包括: 1. **跨平台性**:Java代码...
### C#多线程探索详解 #### 多线程概念及优势 在现代操作系统中,如Windows 2000及以上版本,用户可通过任务管理器查看正在运行的程序和进程。进程是运行中的程序,包括其所使用的内存和系统资源。线程作为进程中...
通过本教程的学习,您不仅能够理解Java线程的基本概念,还能掌握多线程编程的核心技巧,为进一步探索Java并发编程打下坚实的基础。随着实践经验的积累,您将能够更加自如地利用多线程来解决实际问题,提升程序性能和...
《Java编程思想习题答案代码》是一份针对学习Java编程思想的宝贵资源,它提供了书中的课后习题解答,旨在帮助学习者在探索Java语言的过程中进行实践和检验自己的理解。这份资料通常与《Thinking in Java》这本书配套...
网络编程中的多线程应用广泛,例如在服务器端,多线程可以用于处理来自不同客户端的并发请求,每个线程负责一个连接,这样可以大大提高服务器的吞吐量。此外,多线程还可以用于异步I/O操作,如下载大文件时,一个...
此外,多线程编程也是这段时间的重点,包括线程的创建、同步和通信,这在并发处理和性能优化中非常关键。 第六十一天至第七十五天,你将学习Java I/O流,这是处理文件和网络通信的基础。你将了解流的概念,以及如何...
- Java提供了多种并发工具类,如`ExecutorService`、`CountDownLatch`、`CyclicBarrier`等,用于简化多线程编程过程中的复杂性。 #### 四、实践建议 - 牢固掌握Java多线程基础知识是应对面试及日常开发的基础。 -...
在Java编程语言中,线程是并发执行任务的基本单元。多线程编程是现代软件开发中的重要组成部分,尤其是在服务器端应用程序、游戏开发以及实时系统中。这个“Java实例 - 获取所有线程源代码+详细指导教程”压缩包,很...
对于有经验的开发者,深入到并发编程或数据库操作的示例中,可以提升他们在实际项目中的技能。 标签中提到的"另类其它"可能暗示了这个资源中包含了一些非主流或者不常见的Java技术或者应用场景,这为学习者提供了...
源代码可能涉及并发编程,如同步控制(synchronized关键字)、线程池(ExecutorService)等。 7. **反射**:反射机制允许在运行时检查类、接口、字段和方法的信息,甚至动态调用方法。书中源代码可能会展示如何使用...