1. 读写锁
读可以被多个线程一起读
写只能有一个线程去写
读写锁为了更加细粒度的控制
独占锁(写锁)
共享锁(读锁)
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadAndWrite {
public static void main(String[] args) {
Cathe cathe = new Cathe();
for (int i = 0; i < 9; i++) {
int temp = i;
new Thread(()->{
cathe.put(temp + "",temp + "");
}).start();
}
for (int i = 0; i < 9; i++) {
int temp = i;
new Thread(()-> {
cathe.get(temp + "");
}).start();
}
}
}
//定义一个自己的缓存
class Cathe{
private Map<String,String> map = new HashMap<>();
//创建可重入读写锁
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key,String value){
//加上写锁
readWriteLock.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "正在写");
map.put(key,value);
System.out.println(Thread.currentThread().getName() + "写完了");
}finally {
//写锁的释放
readWriteLock.writeLock().unlock();
}
}
public String get(String key){
//加上读锁
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "正在读");
System.out.println(Thread.currentThread().getName() + "读完了");
return map.get(key);
}finally {
//读锁释放
readWriteLock.readLock().unlock();
}
}
}
2. 阻塞列队BlockingQuene
(要知道 Deque(双端队列),AbstractQuene(非阻塞队列))
写入时:队列满了就要阻塞等待
读取时:队列是空的也要阻塞等待
常用的实现类
ArrayBlockingQuene
LinkedBlockingQuene
SynchronousQuene
4组常用API
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
public class BlockQueue {
public static void main(String[] args) throws InterruptedException {
//test01();
//test02();
//test03();
//test04();
test05();
}
public static void test01(){
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
//第一组API add和remove 在队满再添加 或者 列队无再取报异常
blockingQueue.add("AAA");
blockingQueue.add("BBB");
blockingQueue.add("CCC");
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.element());//拿出队头的元素
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
//System.out.println(blockingQueue.remove());
}
public static void test02(){
//第二组 offer poll 队满再添加返回false 队空再去返回null 不会报错
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.offer("aaa");
blockingQueue.offer("bbb");
blockingQueue.offer("ccc");
System.out.println(blockingQueue.offer("ddd"));
System.out.println("======");
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.peek());//拿出排头的元素
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
}
public static void test03() throws InterruptedException {
//第三组API 是put 队满的时候再添加会一直阻塞 take 队空的时候再移除会一直阻塞
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.put("aaa");
blockingQueue.put("bbb");
blockingQueue.put("ccc");
//blockingQueue.put("ddd");
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
}
public static void test04() throws InterruptedException {
//又回到了这里, offer 和 poll 可以设置等待时间 满了再添加,等待几秒,不行就掠过 poll也是同理,等完之后取不到就返回null
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.offer("aaa");
blockingQueue.offer("bbb");
blockingQueue.offer("ccc");
blockingQueue.offer("ddd",3, TimeUnit.SECONDS);
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
}
public static void test05(){
//SynchronousQueue同步队列,与其他队列不同,不存储元素,进入一个,就拿出来一个
BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "正在进入");
blockingQueue.put("a");
System.out.println(Thread.currentThread().getName() + "正在进入");
blockingQueue.put("b");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "正在拿出");
blockingQueue.take();
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "正在拿出");
blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
3. 线程池
池化技术
优化资源的使用,实现线程的复用,能控制最大的并发数量
用一个池子准备好资源,谁来谁拿,用完放回来。
1.降低资源的消耗
2.提高响应速度
3.管理方便
三大方法
Executors工具类有三个创建线程池的方法
newSingleThreadExecutor()单线程池
newFixedThreadExecutor()固定大小的线程池
newCathedThreadExecutor()最大数无限大(21亿)
线程池用完要 shutdown()
但是不采用这种方式创建线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
//ExecutorService pool = Executors.newSingleThreadExecutor(); //创建的单一的线程池
//ExecutorService pool = Executors.newFixedThreadPool(3); //创建固定大小的线程池
ExecutorService pool = Executors.newCachedThreadPool(); // 创建可伸缩的线程池
try {
for (int i = 0; i < 33; i++) {
pool.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
}finally {
pool.shutdown();
}
}
}
七大参数
用ThreadPoolExecutor()方法创建
最大线程的承载是 最大线程数+阻塞队列大小
源码分析
public ThreadPoolExecutor(int corePoolSize, //核心大小,在一般情况下,准备出来的线程数
int maximumPoolSize,//最大线程数,在线程数量需求变大时,会逐渐的开启线程,直到最大线程的大小
long keepAliveTime,//存活时间,emm,就是最大线程数在多久没有任务执行的时候会自动释放
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
四种拒绝策略
扫描二维码关注公众号,回复: 11172003 查看本文章
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
//拒绝策略ThreadPoolExecutor.AbortPolicy() 在达到最大承载的时候,再来人就会报错,并把这个新来的线程丢弃
// CallerRunsPolicy() 在达到最大承载的时候,再来线程会让他原路返回,回到创建这个线程的线程,就像是回到main方法,由main方法执行
// DiscardOldestPolicy() 在达到最大承载的时候,再来线程会尝试让这个线程与最早来的线程竞争,抢过了就执行,抢不过,就丢弃
// DiscardPolicy() 在达到最大承载的时候,直接让新来的线程丢弃
//最大线程数量的定义策略(调优)
//1.CPU密集型
//让他的核数是几 就让它最大的线程数量是几
// Runtime.getRuntime().availableProcessors();
//使用如上方法,来获取CPU的最大核数,不能将最大线程数用常数写死
//2.IO密集型
//根据IO程序最大的线程设置,大于这个线程数
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5,
3, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy());
try {
for (int i = 0; i < 10; i++) {
threadPoolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
}finally {
//用完关闭线程池
threadPoolExecutor.shutdown();
}
}
}
4. 四大函数式接口
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class FourFunctions {
//四大函数式接口
public static void main(String[] args) {
/* Function<String, String> function = new Function<String, String>() {
@Override
public String apply(String o) {
return "进来一个东西出一个东西";
}
};
System.out.println(function.apply("o"));*/
Function<String,String> function1 = (a)->{ return a; };
System.out.println(function1.apply("Lambda"));
//直接给你消费掉
/* Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("进来啥,消费啥");
}
};
consumer.accept("???");*/
Consumer<String> consumer = (a)->{
System.out.println("爷,进来进出不去了拉,来玩呀");
};
consumer.accept("!!!");
//慈善家,供给你
Supplier<String> supplier = ()->{
return "感受supplier的爱吧!";
};
System.out.println(supplier.get());
//断定型,直接给你审判了
Predicate<String> predicate = (a)->{
System.out.println("迎接审判吧!!!");
return true;
};
System.out.println(predicate.test("!!!"));
}
}
5. 面试会问到的流式计算
import java.util.Arrays;
import java.util.List;
/**
* 题目要求:一分钟一行代码完成此题
* 1.ID必须是偶数
* 2.年龄大于23岁
* 3.用户名转变为大写字母
* 4.用户倒叙排序
* 5.只输出一个用户
*/
public class Stream {
public static void main(String[] args) {
User user1 = new User(1,"a",21);
User user2 = new User(2,"b",22);
User user3 = new User(3,"c",23);
User user4 = new User(4,"d",24);
User user5 = new User(5,"e",25);
User user6 = new User(6,"f",26);
List<User> users = Arrays.asList(user1, user2, user3, user4, user5, user6);
users.stream().filter(user -> {return user.getId()%2 == 0;})
.filter(user -> {return user.getAge() > 23;})
.map(user -> {return user.getName().toUpperCase();})
.sorted((u1,u2)->{return -1;})
.limit(1L)
.forEach(System.out::println);
}
}
class User{
private int id;
private String name;
private int age;
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 "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
6. ForkJoin
JDK1.7中引入,并行执行任务,提高效率,用于大数据的情况下。
把大任务化成小任务,最后汇成结果(递归)
特点:工作窃取,某个线程把任务执行完,还会取窃取其他线程没有执行完的任务(维护的是双端队列)
ForkJoin的执行过程
创建ForkJoinPool(用来执行任务)
ForkJoinTask的两个类型 RecurisiveTask有返回值 RecursiveAction无返回值
创建自己的ForkJoinTask要继承这两个类
fork()把方法压入
join()获取结果
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;
public class ForkJoinDemo extends RecursiveTask<Long> {
private Long start;
private Long end;
private Long middle = 10000L;
public ForkJoinDemo(Long start, Long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if((end - start) < middle){
Long sum = 0L;
for(Long i = start;i <= end;i++){
sum += i;
}
return sum;
}else{
long mid = (start + end) / 2;
ForkJoinDemo task1 = new ForkJoinDemo(start,mid);
task1.fork();
ForkJoinDemo task2 = new ForkJoinDemo(mid + 1,end);
task2.fork();
return task1.join() + task2.join();
}
}
}
class test{
public static void main(String[] args) throws ExecutionException, InterruptedException {
//test01(); //939
//test02(); //459
test03(); //97
}
//普通程序员
public static void test01(){
Long sum = 0L;
long start = System.currentTimeMillis();
for (Long i = 1L;i <= 100000000;i++){
sum += i;
}
long end = System.currentTimeMillis();
System.out.println("和为" + sum + "时间为" + (end-start));
}
//ForkJoin
public static void test02() throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinDemo task = new ForkJoinDemo(0L, 100000000L);
ForkJoinTask<Long> submit = forkJoinPool.submit(task);
Long sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("和为" + sum + "时间为" + (end-start));
}
//Stream并行流
public static void test03(){
long start = System.currentTimeMillis();
long sum = LongStream.rangeClosed(0L, 100000000L).parallel().reduce(0,Long::sum);
long end = System.currentTimeMillis();
System.out.println("和为" + sum + "时间为" + (end-start));
}
}
7. 异步回调
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class Asyn {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
//没有返回值的异步回调
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("无返回值的延迟异步回调");
});
System.out.println("Main函数");
//获取阻塞的执行结果
completableFuture.get();
*/
//有返回值的异步回调
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName());
int i = 1/0;
return 200;
});
//completableFuture.whenComplete 首先若是正常执行的化,则进行返回200的语句
//若上方代码有错误,那么则会走exceptionally的代码,返回404
CompletableFuture<Integer> future = completableFuture.whenComplete((t, v) -> {
System.out.println("t:" + t);
System.out.println("v:" + v);
}).exceptionally(e -> {
System.out.println(e.getMessage());
return 404;
});
//get的值是返回值
System.out.println(future.get());
}
}