JUC学习-5-ReadWriteLock-ArrayBlockingQueue-SynchronousQueue-线程池
ReadWriteLock
/*
* 独占锁(写锁)一次只能被一个线程占有
* 共享锁(读锁) 多个线程可以同时占有
* ReadWriteLock
* 读-读 可以共存
* 读-写 不能共存
* 写-写 不能共存
*
* */
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
MyCacheLock myCacheLock = new MyCacheLock();
for (int i = 1; i <= 10; i++) {
int finalI = i;
new Thread(() -> {
myCacheLock.put(finalI + "", finalI);
}, String.valueOf(i)).start();
}
for (int i = 1; i <= 10; i++) {
int finalI = i;
new Thread(() -> {
myCacheLock.get(finalI + "");
}, String.valueOf(i)).start();
}
}
}
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
public void put(String key, Object value) {
System.out.println(Thread.currentThread().getName() + "写入" + key);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写入OK");
}
public void get(String key) {
System.out.println(Thread.currentThread().getName() + "读取" + key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取OK");
}
}
class MyCacheLock {
private volatile Map<String, Object> map = new HashMap<>();
// 读写锁 更加细粒度的操作
// 写的时候只能有一个线程写 读的时候所有人都可以读
private ReadWriteLock lock = new ReentrantReadWriteLock();
public void put(String key, Object value) {
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + "写入" + key);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写入OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
public void get(String key) {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + "读取" + key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
}
阻塞队列
写入:如果队列满了,就必须阻塞等待
取:如果队列是空的,必须阻塞等待生产
什么情况下我们回使用阻塞队列 多线程并发处理 线程池
学习使用队列
四组API
方式 | 抛出异常 | 不会抛出异常/有返回值 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer | put | offer(e, timeout, unit) |
移除 | remove | poll | take | poll(timeout, unit) |
检测队首元素 | element | peek | - | - |
/*
* 抛出异常
* */
public static void tesst1() {
ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(bockingQueue.add("a"));
System.out.println(bockingQueue.add("b"));
System.out.println(bockingQueue.add("c"));
// java.lang.IllegalStateException Queue full 队列已满
// System.out.println(bockingQueue.add("d"));
System.out.println(bockingQueue.remove());
System.out.println(bockingQueue.remove());
System.out.println(bockingQueue.remove());
// 查看队首元素 java.util.NoSuchElementException 无元素
// System.out.println(bockingQueue.element());
// java.util.NoSuchElementException 无元素
// System.out.println(bockingQueue.remove());
}
/*
* 不会抛出异常/有返回值
* */
public static void tesst2() {
ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(bockingQueue.offer("a"));
System.out.println(bockingQueue.offer("b"));
System.out.println(bockingQueue.offer("c"));
// 返回false
System.out.println(bockingQueue.offer("d"));
System.out.println(bockingQueue.poll());
System.out.println(bockingQueue.poll());
System.out.println(bockingQueue.poll());
// 返回null
System.out.println(bockingQueue.peek());
// 返回null
System.out.println(bockingQueue.poll());
}
/*
* 阻塞等待 (一直阻塞)
* */
public static void test3() throws InterruptedException {
ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
bockingQueue.put("a");
bockingQueue.put("b");
bockingQueue.put("c");
// 一直阻塞
// bockingQueue.put("d");
System.out.println(bockingQueue.take());
System.out.println(bockingQueue.take());
System.out.println(bockingQueue.take());
// 一直阻塞
System.out.println(bockingQueue.take());
}
/*
* 阻塞等待 (超时退出)
* */
public static void test4() throws InterruptedException {
ArrayBlockingQueue<Object> bockingQueue = new ArrayBlockingQueue<>(3);
bockingQueue.offer("a");
bockingQueue.offer("b");
bockingQueue.offer("c");
// 2秒超时退出
bockingQueue.offer("d", 2, TimeUnit.SECONDS);
System.out.println(bockingQueue.poll());
System.out.println(bockingQueue.poll());
System.out.println(bockingQueue.poll());
// 2秒超时退出 返回null
System.out.println(bockingQueue.poll(2, TimeUnit.SECONDS));
}
同步队列 SynchronousQueue
没有容量 进去一个 元素,必须等待取出来之后 才能继续添加元素
put take
/*
* 同步队列
* 和其他的BlockingQueue不一样 SynchronousQueue 不存储元素
* put了一个元素 必须从里面take取出来 否则不能再put进去元素
*
* */
public class SynchronousQueueDemo {
public static void main(String[] args) {
SynchronousQueue synchronousQueue = new SynchronousQueue();
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "put1");
synchronousQueue.put("1");
System.out.println(Thread.currentThread().getName() + "put2");
synchronousQueue.put("2");
System.out.println(Thread.currentThread().getName() + "put3");
synchronousQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "T1").start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(synchronousQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "T2").start();
}
}
线程池
三大方法 七大参数 四种拒绝策略
池化技术
程序的运行就会占用系统的资源 优化资源的使用 => 池化技术
线程池 连接池 内纯池 对象池... 创建 销毁非常浪费资源
池化技术: 事先准备好一些资源 有人要用 就来池子里面来拿 用完之后还回来
线程池的好处:
- 降低资源的消耗
- 提高响应的速度
- 方便管理
可以复用 可以控制最大并发数
三大方法
// Executors 工具类 三大方法
// 使用线程池之后 要使用线程池创建线程
public class Demo01 {
public static void main(String[] args) {
// ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
ExecutorService threadPool = Executors.newFixedThreadPool(5);// 创建固定大小的线程池
// ExecutorService threadPool = Executors.newCachedThreadPool();// 可伸缩的
try {
for (int i = 0; i < 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "=====");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 线程池使用完毕后 程序结束 关闭线程池
threadPool.shutdown();
}
}
}
七大参数 源码分析
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
// 本质 ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize, // 核心线程池大小
int maximumPoolSize, // 最大核心线程池大小
long keepAliveTime, // 超时没有人调用就会被释放
TimeUnit unit, // 超时单位
BlockingQueue<Runnable> workQueue, // 阻塞队列
ThreadFactory threadFactory, //线程工厂 创建线程
RejectedExecutionHandler handler) {// 拒绝策略
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
最大承载 = 最大核心线程池大小 + 阻塞队列
四种拒绝策略
AbortPolicy 默认的拒绝策略 队列满了,不处理新来的 抛出异常
CallerRunsPolicy 那来的去哪里
DiscardPolicy 队列满了 丢掉任务 不会抛出异常
DiscardOldestPolicy 队列满了 尝试和最早的竞争 丢掉任务 不会抛出异常
最大线程该如何定义
CPU密集型
多条线程同时执行 几核就是几 可以保证CPU的效率最高
Runtime.getRuntime().availableProcessors() 获得当前电脑的逻辑核心
IO密集型
IO 十分占用资源 判断你的程序有多少个处理IO的的线程,然后留一些给做其他任务做