4.3.1 Lock接口
阻塞队列
package com.wangyi.stduy.lock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class GLBlockQueue {
private List list = new ArrayList();
private Lock lock = new ReentrantLock();
private Condition putCondition = lock.newCondition();
private Condition takeCondition = lock.newCondition();
private int length;
public GLBlockQueue(int length) {
this.length = length;
}
public void put(Object obj) {
lock.lock();
try{
while(true) {
if (list.size() < length) {
list.add(obj);
System.out.println("放入元素" + obj);
takeCondition.signal();
} else {
putCondition.await();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public Object take(){
lock.lock();
try {
if(list.size() > 0){
Object obj = list.remove(0);
System.out.println("取出元素" + obj);
putCondition.signal();
return obj;
}else{
takeCondition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
return null;
}
}
}
public static void main(String[] args) throws InterruptedException {
GLBlockQueue queue = new GLBlockQueue(5);
new Thread(){
@Override
public void run(){
for (int i = 0; i < 20; i++) {
int x = new Random().nextInt(10);
queue.put("X"+ x);
}
}
}.start();
Thread.sleep(1000L);
System.out.println("开始取元素");
for (int i = 0; i < 20; i++) {
queue.take();
}
}
ReentrantLock
锁了2次-解锁1次 锁未释放!
作业:
编写一个高性能MAP,读取支持多线程,写入利用锁来实现一致性。
4.3.2 AQS(AbstractQueuedSynchronizer)
4.3.3.1 并发容器类-map-数组和链表
系统存放数据->数据结构
数组:获取方便、插入麻烦【需要移动元素】
链表:获取麻烦、插入方便
4.3.3.2 并发容器类-map-hashMap初始化概述
数组:获取方便、插入麻烦【需要移动元素】
链表:获取麻烦、插入方便
因为数组获取方便,链表插入方便。所以取他们的长处。由此组成【HashMap】
4.3.3.3 并发容器类-map-红黑树的基本概念
4.3.3.4 并发容器类-map-hashMap的扩容机制
JDK1.7 hashmap 数组+链表
JDK1.8 hashmap 当链表长度小于8时,数组+链表
大于8时,数组+红黑树
4.3.3.5 并发容器类-map-concurrentHashMap
线程安全的MAP
速度比hashtable快
1.不是整体加锁,而是加在node上面,成为一个行锁。
2.需要搞清楚,一,concurrentHashMap用什么方式扩容 二
4.2.4 并发容器类-list_set_queue
1.是个数组
2.扩容时,扩容1.5倍
3.for循环,不要调用原list.add(),会抛异常
CopyOnWriteArrayList
底层:数组
特点:读写并行
实现原理:当发生写操作时,JVM会拷贝原List一个副本,在副本上完成写操作后,将对象的引用地址转移到新的副本地址上。
场景:多读少写
4.3.5 并发协同工具
短跑运动员一起跑!
AQS应用!
4.3.6 FutureTask核心思想
Callable
代码一:
代码二:
实现原理类:
4.3.7 forkjoin并发处理框架
package com.netease.study.juc;
import static java.util.concurrent.Executors.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
public class ForkJoinDemo {
private static List<String> data = new ArrayList<>();
static{
for(int i = 0; i < 100000; i++) {
data.add("Data["+i+"]");
}
}
public static String getData(String value){
return "getData,value is ["+value+"]";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
test1();
test2();
}
private static void test1(){
Long beginTm = System.currentTimeMillis();
System.out.println("任务开始1");
//单线程执行
ExecutorService pool = newFixedThreadPool(1);
Future future = pool.submit(new Task(0,data.size()));
// System.out.println(future.get());
Long endTm = System.currentTimeMillis();
System.out.println("程序执行结束1,执行耗时[" + (endTm - beginTm) + "]");
}
private static void test2(){
long beginTm = System.currentTimeMillis();
ExecutorService pool = newFixedThreadPool(4);
System.out.println("任务开始2");
List<Future> futures = new ArrayList<>();
int size = data.size();
int groupSize = 1000;
int groupCount = (size - 1)/groupSize + 1;
for(int groupIndex = 0; groupIndex < groupCount-1; groupIndex++){
int leftIndex = groupSize * groupIndex;
int rightIndex = groupSize * (groupIndex + 1);
Future future1 = pool.submit(new Task(leftIndex,rightIndex));
futures.add(future1);
}
// for (Future future1 : futures) {
// System.out.println(future1.get());
// }
long endTm = System.currentTimeMillis();
System.out.println("程序执行结束2,执行耗时[" + (endTm - beginTm) + "]");
}
static class Task implements Callable<String>{
int leftIndex;
int rightIndex;
public Task(int leftIndex, int rightIndex) {
this.leftIndex = leftIndex;
this.rightIndex = rightIndex;
}
@Override
public String call() throws Exception {
StringBuffer sb = new StringBuffer();
for(int i = leftIndex;i < rightIndex;i ++){
sb.append(getData(data.get(i)));
}
return sb.toString();
}
}
}