零、Concurrent包概述
jdk5开始提供的 并发工具包,在其中提供了大量的和并发操作相关的工具,大大简化了java的多线程开发。
一、BlockingQueue - 阻塞式队列 不接受 null 元素
BlockingQueue 通常用于一个线程生产对象,而另外一个线程消费这些对象的场景。
操作阻塞式队列的四组方法
抛异常 特定值 阻塞 超时
插入 add(o) offer(o) put(o) offer(o, timeout, timeunit)
移除 remove(o) poll(o) take(o) poll(timeout, timeunit)
检查 element(o) peek(o)
BlockingQueue
|- ArrayBlockingQueue
|- LinkedBlockingQueue
ArrayBlockingQueue
ArrayBlockingQueue 类实现了 BlockingQueue 接口。
ArrayBlockingQueue 是一个有界的阻塞队列,其内部实现是将对象放到一个数组里。
构造方法:
ArrayBlockingQueue(int capacity)
案例:利用阻塞式队列 来实现 生产者 消费者 机制
LinkedBlockingQueue
LinkedBlockingQueue 类实现了 BlockingQueue 接口。
LinkedBlockingQueue 底层是链表 可以设置 最大容量 也可以不设置 如果不设置 默认最大容量为 Integer.MAX_VALUE 可以认为没有容量限制
构造方法:
LinkedBlockingQueue(int capacity)
LinkedBlockingQueue()
二、ConcurrentMap - 并发Map
ConcurrentMap是一种线程安全的Map
ConcurrentMap
| - ConcurrentHashMap
HashMap - 线程不安全 效率高
HashTable - 线程安全 效率低 已经过时 不推荐使用 --- 锁的是整个桶
ConcurrentHashMap - 线程安全 效率比较高 ---锁分段技术,加在正在操作的桶上
ConcurrentHashMap效率:
锁不是加载整个Map上,而是加在正在操作的桶上的,从而在桶的级别实现了并发 提高效率
引入和读写锁,在并发读的过程中 可以并发 提升效率
三、CountDownLatch -- 闭锁 -- 线程递减锁
可以协调多个线程执行的先后顺序,非常便于实现 一个线程的执行需要等待另外一个或多个线程达到指定条件的需求。
构造方法:
CountDownLatch(int count)
阻塞线程:
void await()
递减数字:
void countDown() //没底调用count-1 减到0,则await阻塞被放开
四、CyclicBarrier -- 栅栏
CyclicBarrier是一个所有线程必须等待的一个栅栏,直到指定数量的线程都到达栅栏位置,然后所有线程才可以继续做其他事情。
构造方法 :
CyclicBarrier(int count)
到达栅栏开始等待:
void await();//当足够count个线程进入等待状态,栅栏同时打开阻塞,所有的线程一起向下执行
五、Exchanger -- 交换机
Exchanger 类表示一种两个线程可以进行互相交换对象的会和点
构造方法:
new Exchanger();
交换对象:
exchange(object)
六、Semaphore -- 信号量
计数信号量由一个指定数量的 "许可" 初始化。每调用一次 acquire(),一个许可会被调用线程取走。每调用一次 release(),一个许可会被返还给信号量。
作用:经常用于限制获取某种资源的线程数量
Semaphore(int permits)
Semaphore(int permits, boolean fair)
获取信号量:
void acquire()//如果信号量当前 值为0,则此方法阻塞 直到有release将信号量返回
释放信号量:
void release()//立即释放一个信号,无论是否之前获取过都可以调用此方法,不阻塞
功能1:控制一度重要的代码同一时间内 至多有 n个线程访问
功能2:在两个线程之间传递信号
七、ExecutorService -- ThreadPool -- 执行器服务、线程池
ExecutorService
|-ThreadPoolExecutor
线程池,用来共享线程,线程在需要的时候创建,用完后不销毁,而是存入线程池,则后续再需要使用线程时,可以直接从池中获取线程来使用,从而减少线程的开关次数,提升程序的性能。
(1)通过构造方法创建线程池
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
corePoolSize 核心池大小
maximumPoolSize 最大池大小
keepAliveTime 空闲的多余线程保持时间
unit 时间单位
workQueue 阻塞式队列
handler 拒绝服务助手
(2)通过工具类获取常用的线程池实现
Executors
newCachedThreadPool()
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。
newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池
newSingleThreadExecutor()
创建一个单一线程的线程池
2.执行任务
execute(Runnable)
Future submit(Runnable) //可以通过Future的get()方法来观察任务是否执行结束 --- 全部结束
Future submit(Callable) //可以用来观察任务是否执行结束 并且可以从线程内部带回返回值
invokeAny() //其中一个
invokeAll() //所有的
3.关闭线程池
shutdown()
ExecutorService 并不会立即关闭,但它将不再接受新的任务,而且一旦所有线程都完成了当前任务的时候,ExecutorService 将会关闭
shutdownNow()
这样会立即尝试停止所有执行中的任务, 并忽略掉那些已提交但尚未开始处理的任务。 无法担保执行任务的正确执行。可能它们被停止了,也可能已经执行结束。
八、Lock - 锁
是线程同步的机制 可以实现类似synchronized代码块的效果 但是比synchronized代码更灵活 更简单
ReentrantLock
方法:
lock.lock() 上锁
lock.unlock( ) 解锁
ReadWriteLock 无论多少个读过来,都可以并发处理,写+写|读+写不能并发
这个和上面的用法稍有不同,
lock.readLock().lock(); 上读锁
lock.readLock().unlock(); 解除读锁
lock.writeLock().lock(); 上写锁
lock.writeLock().lock() ; 解除写锁