JAVA基础4-JAVA线程学习笔记(2)

JAVA线程学习笔记(2)

  • 2.1 结构图
  • 2.2 Java中的高级线程工具
    • 2.2.1 java.util.concurrent.atomic
    • 2.2.2 AbstractQueuedSynchronizer
    • 2.2.3 ReentrantLock
    • 2.2.4 Condition
    • 2.2.5 Semaphore
    • 2.2.6 CountdownLatch
    • 2.2.7 CyclicBarrier
    • 2.2.8 Exchanger
  • 2.3 线程池
    • 2.3.1 Callable
    • 2.3.2 Executor
    • 2.3.3 ExecutorService
    • 2.3.4 Executors
    • 2.3.5 ThreadPoolExecutor
    • 2.3.6 ScheduledThreadPoolExecutor
    • 2.3.7 Future
    • 2.3.8 RunnableFuture
    • 2.3.9 FutureTask
    • 2.3.10 CompletionService
    • 2.3.11 ExecutorCompletionService
    • 2.3.12 Fork/Join框架

2.1 结构图

2.2 Java中的高级线程工具

2.2.1 java.util.concurrent.atomic

多线程环境下,无锁的进行原子操作。在Atomic包里一共有12个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装类。
原子更新基本类型类
AtomicBoolean:原子更新布尔类型。compareAndSwapInt
AtomicInteger:原子更新整型。compareAndSwapInt
AtomicLong:原子更新长整型。compareAndSwapLong
相对于没有char、float和double。其实可以使用Unsafe的compareAndSwapObject来实现或者直接使用AtomicReference。

原子更新数组类
AtomicIntegerArray:原子更新整型数组里的元素。
AtomicLongArray:原子更新长整型数组里的元素。
AtomicReferenceArray:原子更新引用类型数组里的元素。

原子更新引用类型
原子更新基本类型的AtomicInteger,只能更新一个变量,如果要原子的更新多个变量,就需要使用这个原子更新引用类型提供的类。Atomic包提供了以下三个类:
AtomicReference:原子更新引用类型。
AtomicReferenceFieldUpdater:原子更新引用类型里的字段。
AtomicMarkableReference:原子更新带有标记位的引用类型。可以原子的更新一个布尔类型的标记位和引用类型。构造方法是AtomicMarkableReference(V initialRef, boolean initialMark)

原子更新字段类
如果我们只需要某个类里的某个字段,那么就需要使用原子更新字段类,Atomic包提供了以下三个类:
AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
AtomicLongFieldUpdater:原子更新长整型字段的更新器。
AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更数据和数据的版本号,可以解决使用CAS进行原子更新时,可能出现的ABA问题。

2.2.2 AbstractQueuedSynchronizer

提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础。
其中acquire和release是获取资源和释放资源的方法。
继承者需要实现tryAcquier和tryRelease方法。基本利用使用CAS的原子性实现即Unsafe类。

2.2.3 ReentrantLock

分类:非公平锁和公平锁
JAVA基础4-JAVA线程学习笔记(2)_第1张图片
JAVA基础4-JAVA线程学习笔记(2)_第2张图片
是java1.6之后加入的,实现Lock接口,修补synchronized的一些缺陷。包括可以采用不同调度算法,加了类似锁投票、定时锁等候和可中断锁等候的一些特性。基于AbstractQueuedSynchronizer实现的,实现tryAcquire和tryReleace方法,然后给予lock和unlock使用。
方法:
Lock:锁住资源,如果竞争会处于休眠。
Unlock:解锁。
Trylock:尝试锁,如果成功,锁定资源,不成功直接返回。返回boolean,true为锁定成功。
Java中应用
阻塞队列都是使用reentrantlock锁。

2.2.4 Condition

条件变量很大一个程度上是为了解决Object.wait/notify/notifyAll难以使用的问题。
条件(也称为条件队列 或条件变量 )为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。
通过Lock的newConditon方法获取锁。如下例子:
JAVA基础4-JAVA线程学习笔记(2)_第3张图片

2.2.5 Semaphore

是一种基于计数的信号量(可以理解为多个资源锁)。也是基于AbstractQueuedSynchronizer实现其功能,实现tryAcquire和tryReleace方法。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做完自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。
初始方法包括信号量和公平锁。
常用方法:acquire、tryAcquire和release方法。
应用场景:线程池等有限资源应用场所。

2.2.6 CountdownLatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。也是基于AbstractQueuedSynchronizer实现其功能。CountdownLatch相对于Thread.join功能,等待其它线程都完成后,主线程再继续。
常用方法:countDown(线程完成工作则减一)和await(等待所有线程完成工作)
注意事项:必须等到计数器为0是,才会跳出await(await一般是主线程调用)。
应用场景:个主线程等待一组工作线程的任务完毕。

2.2.7 CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。内部使用reentrantLock实现。
常用方法:await。
注意事项:CyclicBarrier.await() 方法会抛出一个独有的 BrokenBarrierException。这个异常发生在当某个线程在等待本 CyclicBarrier 时被中断或超时或被重置时,其它同样在这个 CyclicBarrier 上等待的线程便会受到 BrokenBarrierException。意思就是说,同志们,别等了,有个小伙伴已经挂了,咱们如果继续等有可能会一直等下去,所有各回各家吧。
应用场景:一组线程需要在一个时间点上达成一致。其实CyclicBarrier与countdownLatch基本可以互换写出同样功能,只是CyclicBarrier循环特性(再次调用 await() 方法,计数就又会变成 N-1)和构造函数所接受的 Runnable 参数也是 CountDownLatch 所不具备的。

2.2.8 Exchanger

以在两个线程之间交换数据,只能是2个线程,他不支持更多的线程之间互换数据。
主要方法:exchange,入参是将数据传输到另外一个线程,返回参数是获取另外线程的数据,会发生阻塞当一个线程没有交换数据时。
应用场景:一般用于2线程数据交换。

2.3 线程池

JAVA基础4-JAVA线程学习笔记(2)_第4张图片

2.3.1 Callable

理解为一个拥有返回值的Runable。可以被线程池执行。

2.3.2 Executor

定义一个接口,描述将运行 Runnable 的对象。void execute(Runnable command)

2.3.3 ExecutorService

定义一个接口,并继承Executor。扩展Executor的功能,包括shutdown、shutdownNow、submit(Runnable)等方法。一般线程池都实现此接口。

2.3.4 Executors

Java.util.concurrent中提供多个线程池的实现,但是一般不会通过new直接新建线程池,而是通过工厂模式实现,Executors 类就是包含用于构造许多不同类型的 Executor 实现的静态工厂方法。以下几个常用方法介绍:
Executors.newCachedThreadPool() 创建不限制大小的线程池,但是当以前创建的线程可以使用时将重新使用那些线程。如果没有现有线程可用, 将创建新的线程并将其添加到池中。使用不到 60 秒的线程将终止并从缓存中删除。
Executors.newFixedThreadPool(int n) 创建线程池,其重新使用在不受限制的队列之外运行的固定线程组。在关闭前,所有线程都会因为执行过程中的失败而终止,如果需要执行后续任务,将会有新的线程来代替这些线程。
Executors.newSingleThreadExecutor() 创建 Executor,其使用在不受限制的队列之外运行的单一工作线程,与 Swing 事件线程非常相似。保证顺序执行任务,在任何给定时间,不会有多个任务处于活动状态。
newSingleThreadScheduledExecutor()和newScheduledThreadPool(int corePoolSize),创建的是个ScheduledThreadPoolExecutor,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程。

2.3.5 ThreadPoolExecutor

实现ExecutorService接口,并实现其方法。可以设置线程池数量、存活时间等。其中有一个参数是ThreadFactory,是一个工厂类,其构造执行程序要使用的新线程,使用定制的线程工厂,创建的线程可以包含有用的线程名称,并且这些线程是守护线程,属于特定线程组或具有特定优先级。
JAVA基础4-JAVA线程学习笔记(2)_第5张图片
在工厂类Executor中,newFixedThreadPool 和 newCachedThreadPool 工厂方法返回的 Executor 就是类 ThreadPoolExecutor 的实例。
ThreadPoolExecutor 参数的中药含义:

名称 类型 含义
corePoolSize int 核心线程池大小
maximumPoolSize int 最大线程池大小
keepAliveTime long 线程最大空闲时间
unit TimeUnit 时间单位
workQueue BlockingQueue 线程等待队列
threadFactory ThreadFactory 线程创建工厂
handler RejectedExecutionHandler 拒绝策略

ThreadPoolExecutor任务处理流程:
JAVA基础4-JAVA线程学习笔记(2)_第6张图片

2.3.6 ScheduledThreadPoolExecutor

继承ThreadPoolExecutor类,并实现ScheduledExecutorService接口。是一个轮询功能的线程池。增加schedule和scheduleWithFixedDelay方法,使用定时执行任务。Schedule是多久之后执行一次任务,但只会执行一次。scheduleWithFixedDelay是多久之后执行一次任务,会不断执行。

2.3.7 Future

线程返回的结果。使用get方法可以获得线程结束的返回结果。但是get会阻塞,如果线程没有结束的话。

2.3.8 RunnableFuture

继承Runable和Future的即可,实现此接口的既可以作为线程也可以作为返回值。

2.3.9 FutureTask

实现RunnableFuture接口,并实现其方法。此类既可以作为线程也可以作为线程返回值。

2.3.10 CompletionService

CompletionService整合了Executor和BlockingQueue的功能。你可以将Callable任务提交给它去执行,然后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,像一个打包的Future。

2.3.11 ExecutorCompletionService

ExecutorCompletionService是实现CompletionService接口的一个类,并将计算任务委托给一个Executor。

2.3.12 Fork/Join框架

主要功能即将一个任务拆分为多个子任务执行,最终再将子任务的执行结果合并(了解Hadoop的童鞋此时应该想起了Hadoop的MapReduce)。

你可能感兴趣的:(JAVA基础)