第9章 并发编程及线程池
JAVA编程中的并发编程技巧

JAVA编程中的并发编程技巧在Java编程中,并发编程是一个非常重要的话题,因为多线程的应用程序在当今的软件开发中非常常见。
并发编程技巧可以提高程序的性能和效率,但同时也会引入一些潜在的问题,例如竞争条件和死锁。
在这篇文章中,我们将探讨一些Java并发编程中常用的技巧,以帮助开发人员更好地利用多线程编程。
1.使用线程池线程池是一个管理线程的工具,它可以帮助开发人员在需要时重复使用线程,而不是不断地创建新的线程。
这样可以减少资源消耗和提高性能。
在Java中,可以使用Executor框架来创建线程池。
Executor框架提供了一组用于管理线程池的接口和类。
```javaExecutorService executor = Executors.newFixedThreadPool(5);executor.submit(new MyTask();executor.shutdown(;```2.使用同步机制在并发编程中,多个线程可能会同时访问共享的资源,因此需要对这些资源进行同步。
在Java中,可以使用synchronized关键字或者ReentrantLock类来实现同步。
以下是一个使用synchronized关键字的例子:```javapublic synchronized void incremencount++;```3.使用并发集合类Java提供了一些并发集合类,例如ConcurrentHashMap和CopyOnWriteArrayList,这些类可以在多线程环境下安全地操作集合。
使用这些并发集合类可以避免在自己的代码中实现同步逻辑。
```javaConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(;map.put("key", "value");```4. 使用volatile关键字在Java中,volatile关键字可以用来标记一个变量,保证其在多线程环境下的可见性。
java中实现并发的方法

java中实现并发的方法Java是一种面向对象的编程语言,它在并发编程方面提供了多种实现方法。
并发编程指的是同时执行多个任务的能力,这在处理大量数据或高负载时非常重要。
本文将介绍Java中实现并发的几种常用方法。
1. 线程(Thread)线程是Java中最基本的并发编程方法。
通过创建多个线程,可以实现并行执行多个任务。
在Java中,可以通过两种方式创建线程:继承Thread类或实现Runnable接口。
继承Thread类需要重写run()方法,而实现Runnable接口需要实现run()方法。
通过调用start()方法启动线程,线程将在自己的独立执行路径上执行任务。
2. 线程池(ThreadPoolExecutor)线程池是一种管理和复用线程的机制,可以避免频繁创建和销毁线程的开销。
Java提供了ThreadPoolExecutor类来实现线程池。
通过创建一个线程池,可以将任务提交给线程池,线程池会自动分配线程来执行任务。
线程池还可以控制并发线程的数量,避免系统资源被过度占用。
3. Callable和FutureCallable是一个带有返回值的任务,与Runnable接口类似,但它可以返回执行结果。
Java提供了Future接口来表示异步计算的结果。
通过调用submit()方法提交Callable任务给线程池,将返回一个Future对象,可以使用该对象获取任务的执行结果。
4. 并发集合(Concurrent Collections)Java提供了一些并发安全的集合类,例如ConcurrentHashMap、ConcurrentLinkedQueue等。
这些集合类在多线程环境下使用时,可以避免出现线程安全问题。
并发集合类采用了一些特殊的数据结构和算法来保证线程安全性,能够高效地处理并发访问。
5. 锁(Lock)锁是一种同步机制,可以保证多个线程对共享资源的互斥访问。
Java提供了synchronized关键字来实现锁机制,也提供了Lock接口及其实现类来实现更加灵活的锁。
JAVA线程与并发编程基础教程

JAVA线程与并发编程基础教程第一章:引言1.1 什么是线程与并发编程1.2 线程与进程的关系1.3 并发编程的优势与挑战第二章:Java中的线程模型2.1 线程的生命周期2.2 线程的状态转换2.3 管理线程的方式第三章:创建与启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程3.3 Callable与Future接口创建线程3.4 启动线程的方式与顺序第四章:线程的同步与互斥4.1 什么是线程同步4.2 synchronized关键字实现同步4.3 Lock与Condition接口实现同步4.4 volatile关键字实现线程间数据可见性 4.5 线程间的等待与唤醒第五章:线程池与任务调度5.1 什么是线程池5.2 Java中的线程池框架5.3 线程池的参数与配置5.4 任务调度与定时执行5.5 线程池的监控与管理第六章:并发编程的挑战与解决方案6.1 并发编程中的常见问题6.2 死锁与活锁6.3 饥饿与公平性6.4 安全发布与线程封闭6.5 并发编程中的性能问题与解决方案第七章:并发集合类7.2 ConcurrentLinkedQueue7.3 CopyOnWriteArrayList7.4 BlockingQueue与DelayQueue 7.5 并发集合类的应用场景第八章:线程间的通信与协作8.1 什么是线程间通信与协作8.2 wait与notify机制8.3 Condition接口的使用8.4 线程间的数据交换与共享第九章:原子操作与无锁编程9.1 什么是原子操作9.2 Java中的原子操作类9.3 无锁编程的概念与特点9.4 并发编程中的ABA问题9.5 原子操作与无锁编程的应用第十章:并发编程工具类10.2 CyclicBarrier10.3 Semaphore10.4 CompletableFuture与FutureTask 10.5 并发编程工具类的使用场景第十一章:性能调优与测试11.1 如何进行性能测试11.2 性能调优的方法与技巧11.3 Java中常见的性能问题11.4 JVM调优与GC优化11.5 并发编程中的性能优化策略第十二章:并发编程的最佳实践12.1 并发编程的最佳实践原则12.2 如何编写线程安全的代码12.3 并发编程中的设计模式12.4 并发编程的调试与排查技巧12.5 并发编程的未来发展与趋势通过以上章节的学习,读者将逐步掌握Java线程与并发编程的基础知识与技术。
线程池的使用和运行流程

线程池的使用和运行流程什么是线程池?线程池是一种常用的并发编程技术,通过预先创建一组线程,并将多个任务分配给这些线程来执行,以提高程序的性能和资源利用率。
线程池可以管理和控制线程的创建、执行和销毁,减少了线程创建和销毁的开销,同时也能够有效地控制线程数量,避免资源过度消耗问题。
线程池的优势使用线程池有以下优势:1.降低线程创建和销毁的开销:线程池在初始化时创建了一组线程,并在需要执行任务时重复利用这些线程,避免了频繁创建和销毁线程的开销。
2.控制线程数量:线程池可以设定最大线程数,防止线程过多导致系统资源耗尽,并可以根据任务负载动态调整线程池的大小。
3.提高程序性能和响应速度:线程池可以通过并发执行多个任务,从而提高程序的执行效率和响应速度。
4.提供线程管理和监控功能:线程池可以提供对线程的管理和监控,例如线程的状态、线程执行的任务数等。
线程池的使用步骤使用线程池可以按照以下步骤进行:1.创建线程池对象:使用线程池需要创建一个线程池对象,可以使用内置的线程池类或自定义线程池类进行创建。
2.提交任务:将需要执行的任务提交给线程池。
任务可以是实现Runnable接口或Callable接口的类。
3.执行任务:线程池会从池中选取一个线程来执行提交的任务,直到任务全部执行完毕或线程池关闭。
4.关闭线程池:当不再需要线程池时,需要显式地关闭线程池,释放资源。
可以调用线程池的shutdown()方法来关闭线程池。
线程池的运行流程线程池的运行流程如下:1.线程池初始化:在创建线程池对象时,需要根据需要设定线程池的参数,例如线程池的大小、任务队列的大小、拒绝策略等。
2.任务提交:将需要执行的任务提交给线程池,线程池将任务存放在任务队列中。
3.任务执行:线程池从任务队列中取出任务,并选择一个线程来执行任务。
线程执行完任务后,会继续从任务队列中取任务执行,直到任务队列为空。
4.线程管理:线程池会管理线程的状态和生命周期。
C语言技术的多线程与并发编程指南

C语言技术的多线程与并发编程指南在计算机科学领域中,多线程和并发编程是非常重要的概念。
它们可以提高程序的性能和效率,使得程序能够同时处理多个任务。
而C语言作为一种广泛应用的编程语言,也提供了一些强大的工具和技术来实现多线程和并发编程。
本文将为读者介绍C语言技术的多线程与并发编程指南。
一、多线程和并发编程的基本概念在开始讨论C语言技术之前,我们先来了解一下多线程和并发编程的基本概念。
多线程是指在一个程序中同时运行多个线程,每个线程都有自己的执行路径和执行状态。
而并发编程则是指程序的多个部分可以同时执行,无需等待其他部分的完成。
二、C语言中的多线程编程在C语言中,多线程编程主要依赖于线程库。
C语言提供了一些线程库,如POSIX线程库(pthread)和Windows线程库等。
这些库提供了一系列的函数和数据结构,用于创建、管理和同步线程。
1. 创建线程在C语言中,可以使用pthread_create函数来创建一个新的线程。
这个函数接受一个函数指针作为参数,用于指定新线程的入口点。
通过这个函数指针,我们可以指定新线程将要执行的代码。
2. 线程同步在多线程编程中,线程同步是一个重要的概念。
它可以确保多个线程之间的操作按照一定的顺序执行,避免出现竞争条件和数据不一致的问题。
C语言提供了一些线程同步的机制,如互斥锁(mutex)和条件变量(condition variable)等。
互斥锁用于保护共享资源,确保在任意时刻只有一个线程能够访问该资源。
通过使用互斥锁,我们可以避免多个线程同时访问共享资源而引发的问题。
条件变量则用于线程之间的通信和协调。
它可以让一个线程等待某个条件的发生,直到其他线程满足条件后发送信号,唤醒等待的线程。
3. 线程池线程池是一种常用的多线程编程技术。
它可以提前创建一定数量的线程,并将它们保存在一个池中。
当需要执行任务时,可以从线程池中获取一个空闲的线程来执行任务,避免了频繁地创建和销毁线程的开销。
C语言的多线程编程与并发执行

多线程编程与并发执行的介绍什么是多线程编程?多线程编程是一种软件开发技术,它允许程序同时执行多个任务。
在传统的单线程编程中,程序在执行完一个任务后才能开始执行下一个任务。
而在多线程编程中,程序可以同时执行多个任务,从而提高了程序的性能和响应速度。
为什么要进行多线程编程?多线程编程可以提高程序的并发性和响应能力。
通过同时执行多个任务,可以使程序更好地利用计算资源,并且可以提高程序的吞吐量和执行效率。
此外,多线程编程还可以简化复杂任务的处理,提高程序的可维护性和扩展性。
多线程编程的基本概念线程线程是程序执行的最小单位,它可以独立执行一段代码。
一个程序可以同时存在多个线程,并且这些线程可以并发执行。
并发执行并发执行是指多个线程同时执行任务的能力。
在多线程编程中,线程可以同时执行不同的任务,从而实现并发执行。
同步与互斥多个线程同时执行时,可能会访问共享资源。
为了保证共享资源的正确性,需要使用同步机制,比如锁和信号量,来实现线程间的互斥和同步。
线程调度线程调度是指操作系统根据一定的策略决定哪个线程先执行,哪个线程暂停执行,以及如何分配计算资源给每个线程。
C语言的多线程编程C语言是一种强大的编程语言,它提供了多线程编程的支持。
C语言中的多线程编程主要通过线程库来实现,比如POSIX线程库(pthread)和Windows线程库。
POSIX线程库(pthread)POSIX线程库是一种用于多线程编程的标准API,它可以让C语言程序在各种操作系统上进行多线程编程。
POSIX线程库提供了一组函数用于创建、管理和同步线程,并且提供了线程调度的支持。
Windows线程库Windows线程库是微软Windows操作系统上的多线程编程支持。
与POSIX线程库类似,Windows线程库也提供了一组函数用于创建、管理和同步线程,并且提供了线程调度的支持。
如何使用C语言进行多线程编程?创建线程在C语言中,可以使用pthread库或Windows线程库来创建线程。
并发编程的基础知识

并发编程的基础知识随着计算机技术的不断发展,现代的计算机系统越来越复杂,为了提高计算机系统的整体性能,现代计算机系统采用了并发编程。
并发编程是指多个任务在同一时间段内同时执行,它利用了多核心处理技术,能够更好地利用计算机系统的资源,提高系统的整体效率。
同时,因为多个任务同时进行,它也能够缩短处理时间,提高对外响应能力。
并发编程是一项核心技术,但是为了开发有效的并发程序,需要掌握一些基础知识。
一、线程和进程线程和进程都是并发编程的基本单位。
进程是应用程序在内存中的执行实例,每个进程都有自己的内存空间和系统资源,它是操作系统资源调度的基本单位。
而线程则是进程的一个执行单元,每个线程共享相同的内存空间和进程资源,线程的创建和撤销要比进程更加快速和高效。
在并发编程中,线程的使用比进程更加普遍。
这是因为进程的切换对操作系统的开销较大,而线程随时可以切换执行,减少了对操作系统的负担。
同时,线程可以共享数据和系统资源,并且数据共享的效率较高。
二、同步与互斥线程之间的协同和操作共享数据需要同步机制的支持。
同步和互斥是并发编程中最基本、最重要的问题之一。
同步是指多个线程之间的时序关系,它用于控制多个线程之间的协作和执行顺序。
比如说,一个线程对共享数据进行了修改,这时另一个线程需要读取这个数据,但是修改操作尚未完成,这时需要等待该线程所做的操作完成后再进行访问操作。
互斥是指同一时刻只有一个线程可以访问共享数据或临界资源,从而避免了多个线程同时修改同一个共享数据所引发的冲突问题。
互斥锁是实现互斥的一种常用机制,线程需要先获取互斥锁才能访问共享资源,完成后再释放互斥锁,以供其他线程使用。
三、死锁死锁是并发编程中一个通常会遇到的问题。
当多个线程尝试获取互斥锁时,如果在执行过程中发生互相等待的情况,就会产生死锁。
比如说,线程A需要获取互斥锁1和互斥锁2,而线程B需要获取互斥锁2和互斥锁1。
如果A先获取锁1,B先获取锁2,接着A尝试获取锁2,因为锁2已经被B获取,A会进入等待状态;而B也因为等待A释放锁1而进入等待状态。
Java并发编程与线程安全技术

Java并发编程与线程安全技术Java并发编程与线程安全技术(标题)介绍Java是一种广泛应用于大型企业级应用程序开发的编程语言。
在这样的应用中,多个任务可能会并发执行。
为了保证该应用的正确性和性能,开发人员需要了解Java的并发编程和线程安全技术。
本文将探讨Java并发编程的基本概念和线程安全技术的实践。
概念并发编程是一种程序设计的范式,它允许多个任务同时执行。
在Java中,线程是实现并发性的基本单位。
线程可以并发地执行多个函数或方法,从而提高应用程序的性能。
但是,并发编程也带来了一些问题,最重要的是线程安全性。
线程安全线程安全是指多个线程并发执行时,程序能够以正确的方式工作。
要实现线程安全,开发人员需要考虑以下几个方面:1. 互斥访问共享数据:当多个线程尝试同时修改共享数据时,可能会导致不确定的结果。
通过使用互斥机制,例如synchronized关键字或锁,可以确保同一时间只有一个线程可以修改共享数据。
2. 有序性:在多线程环境中,线程的执行顺序是无法预测的。
为了确保代码的执行顺序,可以使用volatile关键字,它保证了变量的修改对其他线程是可见的。
3. 线程间通信:在一些场景中,线程需要进行通信以便协调工作。
Java提供了wait()和notify()等方法来实现线程间的通信。
并发编程实践在编写并发程序时,以下几个重要的实践可以帮助确保线程安全:1. 尽量使用不可变对象:不可变对象是指一旦创建,就不可修改的对象。
使用不可变对象可以避免并发修改的问题,因为无法改变的对象是线程安全的。
2. 尽量减少共享数据:共享数据是并发编程中的潜在问题之一。
尽量避免多个线程访问和修改同一个数据对象,可以降低并发编程的复杂性。
3. 合理地使用锁:锁是保护共享数据的重要机制。
合理地使用锁可以防止线程之间的竞争,确保代码的正确性。
但是,过多地使用锁可能会导致性能下降。
4. 使用线程安全的数据结构:Java提供了一些线程安全的数据结构,例如ConcurrentHashMap和CopyOnWriteArrayList。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
阻塞队列
阻塞队列常用于多线程编程中,由于协调线程之间的合作;当队列是空的时 ,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加 元素的操作会被阻塞。 BlockingQueue是个接口,有如下实现类: 1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO( 先进先出)原则对元素进行排序。 2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先 进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是 Integer.MAX_VALUE。 3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对 象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的 Comparator决定的顺序。 4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必 须等待另一个线程移除,反之亦然。
自定义线程池还是具有相当大难度的
JDK自带的线程池
<<interface>> Executor
<<interface>> ExecutorService
AbstractExecutorService
ScheduledExecutorService
ThreadPoolExecutor
ScheduledThreadPoolExecutor
Java并发编程技术 欧阳宏基
本章内容
1.线程池的概念与工作原理 2. Executor并发编程框架以及线程池执行策略 3. Future与Callable 4. 线程锁 5. 利用Condition实现线程间通信 6. 阻塞队列
线程池的概念与工作原理
为什么使用线程池: 假设在一台服务器完成一项任务的时间为T T1 创建线程的时间 T2 在线程中执行任务的时间,包括线程间同步所需时间 T3 线程销毁的时间 那么T = T1+T2+T3。
线程池的执行策略
Executors通过工厂方法提供了四种执行策略来管理工作线程 ,分别是: ①newSingleThreadExecutor:确保所有任务按照提交的先后 顺序由唯一工作线程来执行。 ②newFixedThreadPool:线程数量是固定的,随着任务的提 交而一一创建,直到数量达到最大值。 ③newCachedThreadPool:一个可缓存的线程池,线程池大 小完全依赖于操作系统(或者JVM)能够创建的最大线程数, 并且能根据当前任务的数量来调整线程池中线程的个数,适合 于执行生存周期较短的异步任务。
T1,T3是多线程本身的带来的开销,希望减少T1,T3所用的时间,从而减 少T的时间。如果在程序中频繁的创建或销毁线程,这导致T1和T3在T中占 有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发 性)。 线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器 程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者 一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开 销了。
见源文件:ThreadPoolExecutorTest.java
线程池的执行策略
执行策略是一种资源管理方式,通过限制并发的数量 来确保应用程序不会由于资源耗尽而失败。 执行策略主要从执行任务的线程、任务的执行顺序、 任务并发执行的个数、任务队列中等待执行的个数、 对哪个任务进行拒绝并如何通知应用程序等方面来定 义任务的执行,从而确保应用程序具有较好的性能。
利用Semaphore控制线程并发个数
Semaphore在提供线程同步的基础上,用来控制线程 并发的个数。
(1) 例如有5个座位,10个人要来坐,一次同时能容纳5个人坐, 只能等到有人离开后,其余人才能坐。坐这个座位要获得许可 权,这个许可权就是Semaphore。 (2)剩余的5个人随机获得许可权,或者按照Semaphore设定的 顺序来获得许可权。 见源文件:Semaphore/SemaphoreTest.java
某些情况下,需要执行一组任务,哪个任务先完成,就先取哪个任务的值 。这种情况下可以使用CompletionService。 CompletionService将生产新的异步任务与使用已完成任务的结果分离开 来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,并按 照完成这些任务的顺序处理它们的结果。 见源文件:callable/CompletionServiceTest.java
4
线程池的工作原理
5
创建线程池
要设计一个线程池至少要考虑以下几个方面: ①对任务进行描述的类,包含线程池中线程执行的所 有信息。 ②可动态变化的、保存任务的队列。 ③线程池管理器,用来创建、销毁线程池,提供对任 务的调用与转发。 ④处理任务的工作线程类。 ⑤查询线程,用来检测任务的完成情况。 ⑥拒绝策略。
CyclicBarrier同步工具
一个同步辅助类,它允许一组线程互相等待,直到 到达某个公共屏障点 (common barrier point)。公 共屏障点可以在线程运行过程中设置多次。 例如:大家约好7点在学校门口 集合(屏障),然后一起出发去公 园,到公园后自由活动,下午5 点在公园门口集合(屏障)返回。
见源文件:CountDownLatch/CountDownLatchTest.java
CountDownLatch同步工具
模拟抢红包程序中存在一个缺陷: 最先启动的线程抢到红包的概率是很大的,那么如何 该让所有的线程都具备抢到红包的概率呢?
解决思路:让所有线程都启动后等待一个计数器,当这个计数 器减为0时,再这些线程来执行抢红包的逻辑,这样的话所有 线程的机会都是相等的。
见源文件:BlockingQueue/BlockingQueueTest.java
阻塞队列
应用场景: 可以利用两个只包含一个元素的阻塞队列实现线程同步(生产者消费者)。
Queue1.put() Queue2.put()
Queue2.take() Queue1.put()
Queue1.take()
Queue2.put()
见源文件:BlockingQueue/BlockingQueueTest1.java
相关练习
(1)已知有16个日志对象,在一个线程中每隔1秒打 印一条日志对象,程序源码如备注所示。 要求:在源代码基础上进行修改,要求采用4个线 程在4秒中将日志对象打印完毕。
见源文件:BlockingQueue/BlockingQueueTest2.java
核心线程池对象- ThreadPoolExecutor
ThreadPoolExecutor是线程池体系中的核心类,用来创建和维护线程池对象 。主要属性如下: corePoolSize:核心线程数量(包括空闲线程) maximumPoolsize: 线程池中能创建的最大线程数 keepAliveTime: 当线程数大于核心数时, 空闲线程被销毁前等待任务的最长 时间 unitkeepAliveTime: 参数的时间单位 workQueue: 保存任务的队列,任务实现Runnable接口,由Execute方法调 用执行 threadFactory:创建线程对象所使用的工厂。 handler:由于超出线程范围和队列容量而使执行任务被阻塞时采用的处理程 序
见源文件:ThreadPoolTest.java
④newScheduledThreadPool:创建一个大小无限的线程池。 此线程池支持定时以及周期性执行任务的需求。
见源文件:ScheduledThreadPoolTest.java
Callable&Future
采用实现Runnable接口的线程无法取得返回值。 Callable是接口,其中包含一个call方法,该方法具有返回值。实现 Callable接口的类能够当做多线程中的任务类。 Future类可以拿到Callable的返回值,Future的类型应该与Callable返回值 类型一致。 见源文件:callable/CallableAndFutureTest.java
3
线程池的概念与组成部分
线程池:一种管理一定数量线程的手段,线程池中的线程数量 是由运行时机器容量、负载的配置信息以及动态信息决定。 应用程序在启动时创建一定数量的线程放入线程池,线程池 通过将需要并发运行的任务放入到任务队列中等待空闲线程 来处理。 组成部分: (1) 线程池管理器(ThreadPoolManager):用于创建并管理 线程池 (2) 工作线程(WorkThread): 线程池中线程 (3) 任务接口(Task):每个任务必须实现的接口,以供工作 线程调度任务的执行。 (4) 任务队列:用于存放没有处理的任务。提供一种缓冲机制。
见源文件:lock/LockTest.java 见源文件:lock/BonusTest.java
线程锁
锁的分类: (1) 读锁 (2) 写锁 接口ReadWriteLock 维护了一对相关的锁,一个用于只读操 作,另一个用于写入操作。如果只进行读操作,那么多个线程 可以对同一个共享资源加多次读锁。 写入锁是独占的,用在对共享资源进行修改的情况下。多个线 程要同时进行修改操作,一次只能有一个线程加写锁。在进行 写操作时,不能加读锁。
屏障1
屏障2
见源文件:CyclicBarrier/ CyclicBarrierTest.java
CountDownLatch同步工具
倒计时计数器,调用该对象的countDown()方法将技 术值减1,等到减到0为止,所有等待该计数器的线程 开始运行。 应用场景:在比赛中,所有运动员等到裁判鸣哨,然 后比赛开始,裁判等到所有运动员到终点后,比赛结 束。
线程锁
传统实现线程同步的方法: (1) synchronized代码段 (2) synchronized方法 JDK1.5之后提供了线程锁技术来实现同步 线程锁的特点: (1) 比传统线程技术中的synchronized关键字更加面向对象,在实现互斥( 同步)的代码中,必须要获得相应的锁对象。 (2) 上锁操作的相关代码出现在资源所在类的方法中,而不是线程代码中。