JUC并发编程
进程和线程
进程:
-
一个进程可以包含多个线程。
-
进程是资源分配的最小单位。
线程:
- 线程是资源调度的最小单位。
- java实际上无法开启线程
Runnable没有返回值,效率相比Callable相对较低!
查询cpu核数
public static void main(String[] args) {
//获取cpu的核数
//cpu密集型 IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
并发编程:并发、并行
并行:两个或多个事件在同一个时刻发生。
并发:多个进程指令被快速的轮换执行,同一时刻只有一条指令执行。
并发编程的本质:充分利用cpu资源
wait和sleep的区别:
-
来自不同的类
wait–>Object
sleep–>Thread -
关于锁的释放
wait会释放锁
sleep不会释放锁,会抱着锁睡觉,不释放 -
适用范围不同
wait必须在同步代码块中
sleep可以在任何地方睡 -
是否捕获异常
wait不需要捕获异常
sleep必须捕获异常
传统Synchronize锁
public class SaleTicketDemo01 {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
},"C").start();
}
//资源类
static class Ticket {
//属性 方法
private int number = 50;
//卖票的方式
public void sale() {
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出去" + (number--) + "张票,剩余:" + number);
}
}
}
}
LOCK锁
公平锁:非常公平,不可以插队。
非公平锁:不公平,可以插队。(默认)
lock锁
package com.kang.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SaleTicketDemo02 {
public static void main(String[] args) {
SaleTicketDemo01.Ticket ticket = new SaleTicketDemo01.Ticket();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "C").start();
}
//Lock三部
//1.创建锁 Lock lock = new ReentrantLock();
//2.加锁 lock.lock();
//3.释放锁 lock.unlock();
//资源类
static class Ticket {
//属性 方法
private int number = 50;
Lock lock = new ReentrantLock();
//卖票的方式
public synchronized void sale() {
//加锁
lock.lock();
try {
//业务代码
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出去第" + (number--) + "张票,剩余:" + number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
Synchronize锁和Lock锁区别
- Synchronize 内置的Java关键字 Lock是一个java类
- Synchronize 无法判断获取锁的状态 Lock可以判断是否获取到了锁
- Synchronize会自动释放锁 Lock必须要手动释放锁,如果不释放会死锁
- Synchronize 线程1(获得锁,阻塞) 线程2(持续等待) Lock锁不一定持续等待
- Synchronize 可重入锁,不可以中断,非公平 Lock 可重入锁,可以 判断锁,非公平(可以自己设置)
- Synchronize 适合锁少量的代码同步问题 Lock锁可以锁大量的代码
广义上的可重入锁指的是可重复调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁
锁是什么,如何判断锁!
消费者与生产者问题 Synchronize版本
/*
生产者消费者问题
等待唤醒 通知唤醒
线程交替执行 A B操作同一个变量 num = 0
A num+1
B num-1
*/
import java.util.Date;
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
//等待 业务 通知
class Data { //数字资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
while (number != 0) {
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "-->" + number);
//通知其他线程,我+1完毕了
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
//if 可能会产生虚假唤醒的问题
while (number == 0) {
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "-->" + number);
//通知其他线程,我-1完毕了
this.notifyAll();
}
}
if 解决阻塞状态时,会执行接下来的代码;而使用while,在解除阻塞时,需要直到满足条件才会执行接下来的代码 if判断只判断一次 ,while是满足条件时才执行
采用if判断,唤醒后会从wait之后的代码开始运行,运行过程中不再进行判断。使用while的话,唤醒之后也是从wait之后的代码开始运行,但是唤醒后会重新判断循环条件,如果需要等待则继续等待,不需要等待则执行后续代码。
消费者与生产者问题 Lock版本
public class B {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
//等待 业务 通知
class Data2 { //数字资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// condition.await(); //等待
// condition.signalAll(); //唤醒全部
//+1
public void increment() throws InterruptedException {
lock.lock();
try {
if (number != 0) {
//等待
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "-->" + number);
//通知其他线程,我+1完毕了
this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public void decrement() throws InterruptedException {
lock.lock();
try {
if (number == 0) {
//等待
condition.signalAll();
}
number--;
System.out.println(Thread.currentThread().getName() + "-->" + number);
//通知其他线程,我-1完毕了
this.notifyAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition 精准的通知和唤醒线程
//A执行完调用B,B执行完哇调用C,C执行完调用A
public class C {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printA();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printB();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printC();
}
}, "C").start();
}
static class Data3 { //资源类 lock
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
//1A 2B 3C
private int number = 1;
// private int number =2;
// private int number =3;
public void printA() {
lock.lock();
try {
//业务 判断-> 执行-> 通知
while (number != 1) {
condition1.await();
}
System.out.println(Thread.currentThread().getName() + "-->AAAA");
// 唤醒 唤醒指定的人 B
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (number != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "-->BBBB");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (number != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName() + "--->CCCC");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
8锁现象
- 电话短信问题
//关于锁的8个问题
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendMessage();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone {
//synchronized 锁的对象是方法的调用者
//两个方法用的同一个锁,谁先拿到谁先执行
public synchronized void sendMessage() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送信息");
}
public synchronized void call() {
System.out.println("打电话");
}
}
发送信息
打电话
- 信息与hello问题
package com.kang.lock8;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) {
Phone2 phone2 = new Phone2();
new Thread(()->{
phone2.sendMessage();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.hello();
},"B").start();
}
}
class Phone2 {
//synchronized 锁的对象是方法的调用者
//两个方法用的同一个锁,谁先拿到谁先执行
public synchronized void sendMessage() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送信息");
}
public synchronized void call() {
System.out.println("打电话");
}
//这里没有锁,不是同步方法,不受锁的影响
public void hello() {
System.out.println("hello");
}
}
hello
发送信息
- 两个对象的调用顺序
public class Test3 {
//增加两个静态的同步方法 只有一个对象
public static void main(String[] args) {
// //两个对象的Class类模板只有一个 static 锁的是class
// Phone3 phone1 = new Phone3();
// Phone3 phone2 = new Phone3();
//两个对象 两把锁 两个调用者 按照时间先后顺序来
Phone3 phone3 = new Phone3();
//锁的存在
new Thread(() -> {
phone3.sendMessage();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone3.call();
}, "B").start();
}
}
//Phone3 全局唯一的一个class对象
class Phone3 {
//synchronized 锁的对象是方法的调用者
//static 静态方法
//类一加载就有了 class 模板
public static synchronized void sendMessage() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送信息");
}
public static synchronized void call() {
System.out.println("打电话");
}
//这里没有锁,不是同步方法,不受锁的影响
public void hello() {
System.out.println("hello");
}
}
发送信息
打电话
- 静态方法与普通同步方法
package com.kang.lock8;
import java.util.concurrent.TimeUnit;
public class Test4 {
public static void main(String[] args) {
//一个静态方法 一个普通的同步方法 一个对象
//一个静态方法 一个普通的同步方法 两个对象 静态方法锁的是class模板 下边的
//两个对象的Class类模板只有一个 static 锁的是class
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
//锁的存在
new Thread(() -> {
phone2.sendMessage();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
}, "B").start();
}
}
//Phone4 全局唯一的一个class对象
class Phone4 {
//静态同步方法 锁的是Class类模板
public static synchronized void sendMessage() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送信息");
}
//普通同步方法
public synchronized void call() {
System.out.println("打电话");
}
//这里没有锁,不是同步方法,不受锁的影响
public void hello() {
System.out.println("hello");
}
}
打电话
发送信息
-
静态同步锁和非静态同步方法之间不会有竞争条件,这两把锁是两个不同的对象,非静态同步方法是锁对象,静态同步锁是锁Class模板类。
-
一个静态同步方法获得锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁。
new this 具体的一个手机 实体
static 锁class 是唯一的
如果是同一个锁看谁先得到,如果不是同一个锁,就看是否休眠。
集合类不安全
List不安全
CopyOnWriteArrayList
public class ListTest {
public static void main(String[] args) {
// List<String> list = Arrays.asList("1", "2", "3");
// list.forEach(System.out::println);
/*
并发下ArrayList不安全
解决方案
1.List<Integer> list = new Vector<>();
2.List<Object> list = Collections.synchronizedList(new ArrayList<>());
3.List<Object> list = new CopyOnWriteArrayList<>();
*/
//CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略
//多个线程调用的时候,list,读取的时候,固定的 写入(覆盖)
//在写入的时候避免覆盖,造成数据问题
//读写分离
// synchronized 效率比较低
List<Object> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
CopyOnWriteArraySet
//java.util.ConcurrentModificationException 并发修改异常
public class SetTest {
/*
Set<Integer> set = new HashSet<>(); 不安全
解决方案:
1.Set<Integer> set = Collections.synchronizedSet(new HashSet<>());
2.Set<Integer> set = new CopyOnWriteArraySet<>();
*/
public static void main(String[] args) {
Set<Object> set = new HashSet<>();
for (int i = 1; i <= 10; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}
HashSet底层是什么
public HashSet() {
map = new HashMap<>();
}
//add set 本质就是 map key是无法重复的
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object();//不变的值
ConcurrentHashMap
Map不安全
// java.util.ConcurrentModificationException
public class MapTest {
public static void main(String[] args) {
//工作中不用HashMap Map<Integer, String> map = new HashMap<>(); 不安全
//默认等价于什么 new HashMap<>() 等价于 new HashMap<>(16, 0.75f)
Map<Object, Object> map = new ConcurrentHashMap<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
}).start();
}
//加载因子 初始化容量
//散列表填满的程度
}
}
Callable
- 可以有返回值
- 可以抛出异常
- 方法不同 call()
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// new Thread(new Runnable()).start();
// new Thread(new FutureTask<V>()).start();
// new Thread(new FutureTask<V>(Callable)).start();
new Thread().start(); //怎么启动callable
MyThread thread = new MyThread();
FutureTask futureTask = new FutureTask(thread);//适配类
new Thread(futureTask, "A").start();
new Thread(futureTask, "B").start();
Integer o = (Integer) futureTask.get(); //这个get 方法可能会产生阻塞!把它放到最后
//使用异步通信来处理
System.out.println(o);
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("call()");
return 1024;
}
}
- 有缓存
- 结果可能需要等待 会阻塞
常用辅助类
CountDownLatch (减法计数器)
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//总数是6 必须要执行任务时再使用
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "Go out");
countDownLatch.countDown();//数量-1 ***
}, String.valueOf(i)).start();
}
countDownLatch.await(); //等待计数器归零,然后再向下执行 ***
System.out.println("Close the Door");
}
}
原理:
countDownLatch.countDown();//数量-1
countDownLatch.await(); //等待计数器归零,然后再向下执行
每次有线程用countDown()数量-1,假设计数器变0,countDownLatch.await()就会被唤醒,继续执行
CyclicBarrier (加法计数器)
public class CyclicBarrierDemo {
public static void main(String[] args) {
/*
加法计算器
*/
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("召唤神龙!!!");
});
for (int i = 1; i <= 7; i++) {
final int temp = i;
//lambda 能操作到i吗
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "收集" + temp + "个龙珠");
try {
cyclicBarrier.await();//等待计算器变为7
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
Semaphore
semaphore 信号量
public class SemaphoreDemo {
public static void main(String[] args) {
//线程数量:停车位 限流
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
//acquire() 得到
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "抢到车位");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//release() 释放
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}
原理:
semaphore.acquire(); 得到 假设如果已经满了 等待 等待被释放为止
semaphore.release(); 释放 会将当前的信号量释放+1 然后唤醒等待的线程
作用 : 多个共享资源互斥!并发限流,控制最大的线程数!
读写锁
/*
ReadWriteLock
独占锁(写锁) 一次只能被一个线程占有
共享锁(读锁) 多个线程可以同时占有
读-读 可以共存
读-写 不能共存
写-写 不能共存
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCacheLock myCache = new MyCacheLock();
//写入
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(() -> {
myCache.put(temp + "", temp + "");
}, String.valueOf(i)).start();
}
//读取
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(() -> {
myCache.put(temp + "", temp + "");
}, String.valueOf(i)).start();
}
}
}
//加锁的
class MyCacheLock {
private volatile Map<String, Object> map = new HashMap<>();
//读写锁 更加细粒度的控制
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//存,写 只希望同时只有一个线程写
public void put(String key, Object value) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "写入" + key);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写入完毕" + key);
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
//取
public void get(String key) {
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "读取" + key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取完毕" + key);
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}
/*
自定义缓存
*/
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() + "写入完毕" + key);
}
//取
public void get(String key) {
System.out.println(Thread.currentThread().getName() + "读取" + key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "读取完毕" + key);
}
}
BlockingQueue(阻塞队列 )
阻塞队列:线程池 多线程并发处理
四组API
方式 | 抛出异常 | 有返回值,不抛出异常 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add() | offer() | put() | offer( , ) |
移除 | remove() | poll() | take() | poll( , ) |
检测队首元素 | element() | peek() | - | - |
- 抛出异常
- 不会抛出异常
- 阻塞等待
- 超时等待
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) throws InterruptedException {
test3();
}
/*
抛出异常 有返回值
*/
public static void test1() {
//队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
//IllegalStateException: Queue full
//System.out.println(blockingQueue.add("d"));
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
//NoSuchElementException
// System.out.println(blockingQueue.remove());
}
/*
有返回值 不抛出异常
*/
public static void test2() {
ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
// System.out.println(blockingQueue.offer("d"));//false 不能抛出异常
System.out.println(blockingQueue.element());//检查队首是哪个
System.out.println(blockingQueue.peek());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll()); //null 不抛出异常
}
/*
阻塞等待 一直等
*/
public static void test3() throws InterruptedException {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
blockingQueue.put("d");
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
}
/*
超时等待
*/
public static void test4() throws InterruptedException {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.offer("a");
blockingQueue.offer("b");
blockingQueue.offer("c");
blockingQueue.offer("d",2, TimeUnit.SECONDS);
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
blockingQueue.poll(2,TimeUnit.SECONDS);
}
}
线程池(重点)
池化技术
程序的运行会占用系统的资源,池化技术有助于优化资源的使用
线程池、连接池、内存池、对象池
池化技术:事先贮备一些资源,需要用时来拿,用完还回来
线程池的优点:
- 降低资源的消耗
- 提高响应的速度
- 方便管理
线程复用、可以控制最大并发数、管理线程
线程池 三大方法、七大参数、4种拒绝策略
三种方法
public class Demo01 {
public static void main(String[] args) {
//三种创建方法
ExecutorService threadPool1 = Executors.newSingleThreadExecutor();//单个线程
ExecutorService service = Executors.newFixedThreadPool(5);//创建固定大小的线程池
ExecutorService service1 = Executors.newCachedThreadPool();//可伸缩的
try {
for (int i = 0; i < 10; i++) {
service.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完 程序结束 关闭线程池
service.shutdown();
}
}
}
七种参数
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;
}
四种拒绝策略
1
银行满了,还有人进来,不处理这个人
队列满了,线程数达到最大线程数,还有线程过来,不处理这个线程。抛出异常
new ThreadPoolExecutor.AbortPolicy();
2
哪里来的到哪儿去,由调用线程处理该任务。谁调用,谁处理
new ThreadPoolExecutor.CallerRunsPolicy()
3
队列满了,丢掉任务。不会抛出异常
new ThreadPoolExecutor.DiscardPolicy()
4
队列满了,任务拒绝被添加时 将最早进入队列的任务删除 之后再尝试加入队列 不会抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy());
如何定义最大线程
- CPU密集型 几核就是几,可以保证CPU效率最高
- I/O密集型 判断程序中十分耗I/O的线程 假如有15个十分消耗I/O的大型任务 一般设置为2倍 30
四大函数型接口
函数式接口:只有一个方法的接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
//很多函数式接口
//简化编程模型,在新版本的框架底层大量应用
//foreach(消费者类型的函数式接口)
Function
函数式接口
public class Demo01 {
public static void main(String[] args) {
//工具类 输出输入的值 输入什么 输出什么
//匿名内部类
//1.
Function function = new Function<String, String>() {
@Override
public String apply(String o) {
return o;
}
};
//2.
Function function1 = (s) -> {
return s;
};
System.out.println(function1.apply("asd"));
}
}
Predicate
断定型接口:有一个输入参数,返回只能是布尔值
/*
断定型接口:有一个输入参数,返回值只能是布尔值
*/
public class Demo02 {
public static void main(String[] args) {
//1.
Predicate predicate = new Predicate<String>() {
@Override
public boolean test(String str) {
return str.isEmpty();
}
};
//2.
Predicate<String> predicate1 = (str) -> {
return str.isEmpty();
};
//判断是否为空
System.out.println(predicate1.test("asd"));
}
}
Consumer
Consumer 消费型接口:只有输入,没有返回值
/*
消费型接口 Consumer 只有输入 没有返回值
*/
public class Demo03 {
public static void main(String[] args) {
//1.
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
};
//2.
Consumer<String> consumer1 =(str)->{
System.out.println(str);
};
consumer1.accept("asd");
}
Supplier
Supplier 供给型接口
public class Demo04 {
public static void main(String[] args) {
//没有参数 只有返回值
//1.
Supplier supplier = new Supplier<Integer>() {
@Override
public Integer get() {
System.out.println("get()");
return 1024;
}
};
//2.
Supplier supplier1 = () -> {
return 1024;
};
System.out.println(supplier1.get());
}
}
Stream流式计算
什么是流式计算
大数据 :存储 + 计算
集合、MySQL本质就是存储东西的:
计算应该交给流去做
/*
* 题目要求:一分钟内完成此题,只能用一行代码实现
* 现在有5个用户!筛选
* 1.ID必须是偶数
* 2.年龄必须大于23岁
* 3.用户转为大写
* 4.用户名字母倒着排序
* 5.只输出一个用户
*/
public class Test {
public static void main(String[] args) {
User u1 = new User(1, "a", 21);
User u2 = new User(2, "b", 22);
User u3 = new User(3, "c", 23);
User u4 = new User(4, "d", 24);
User u5 = new User(6, "e", 25);
//集合就是存储
List<User> users = Arrays.asList(u1, u2, u3, u4, u5);
users.stream().filter(u -> {
return u.getId() % 2 == 0;
}).filter(u -> {
return u.getAge() > 23;
}).map(u -> {
return u.getName().toUpperCase();
}).sorted((uu1, uu2) -> {
return uu2.compareTo(uu1);
}).limit(1).forEach(System.out::println);
}
static class User {
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User1{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
Forkjoin
/*
求和计算的任务
Forkjoin Stream并行流
*/
public class ForkJoin extends RecursiveTask<Long> {
private Long start;
private Long end;
//临界值
private Long temp = 10000L;
public static void main(String[] args) {
int sum = 0;
for (int i = 0; i < 1_0000_0000; i++) {
sum += i;
}
System.out.println(sum);
}
public ForkJoin(Long start, Long end) {
this.start = start;
this.end = end;
}
//计算方法
public Long compute() {
if ((end - start) < temp) {
Long sum = 0L;
for (Long i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
long middle = (start + end) / 2; //中间值
ForkJoin task1 = new ForkJoin(start, middle);
task1.fork();
ForkJoin task2 = new ForkJoin(middle + 1, end);
task2.fork();
return task1.join()+task2.join();
}
}
}