异步和线程池

异步和线程池

0. JUC

0.1 wait/sleep

1.sleep 是 Thread 的静态方法,wait 是 Object 的方法,任何对象实例都能调用
2.sleep 不会释放锁,它也不需要占用锁。wait 会释放锁,但调用它的前提是当前线程占有锁(即代码要在 synchronized)

0.2 Lock 与的 Synchronized

1.synchronizedJava 语言的关键字,Lock 是java并发包中实现同步访问的一个类,是一个接口
2.synchronized不需要手动释放锁,当代码执行完成后会自动释放,而Lock则必须要手动解锁,否则会造成死锁
3.Lock 可以让等待锁的线程响应中断,synchronized却不行,等待的线程会一直等待下去,不能够响应中断
4.在性能上来说,当高并发下Lock 的性能要远远优于synchronized
synchronized实现同步,对于普通方法,锁是当前实列对象,静态方法则是当前类的class对象,同步代码块,锁是括号中配置的对象

0.3 安全集合

1.CopyOnWriteArrayList:相当于线程安全的 ArrayList。
原理:
	通过 volatile 和互斥锁来实现的。通过“volatile 数组”来保存数据的。一个线程读取 volatile 数组时,总能看到其它线程对该 volatile 变量最后的写入;就这样,通过 volatile 提供了“读
取到的数据总是最新的”这个机制的保证。通过互斥锁来保护数据。在“添加/修改/删除”数据时,会先“获取互斥锁”,
再修改完毕之后,先将数据更新到“volatile 数组”中,然后再“释放互斥锁”,就达到了保护数据的目的。
2. 线程安全与线程不安全集合
	ArrayList ----- Vector
	HashMap -----HashTable
	以上都是通过 synchronized 关键字实现,效率较低
	Collections 构建的线程安全集合
	.java.util.concurrent 并发包下,CopyOnWriteArrayList CopyOnWriteArraySet 类型,通过动态数组与线程安全个方面保证线程安全

0.4 JUC 三大辅助类

1.CountDownLatch: 减少计数
	当一个或多个线程调用 await 方法时,这些线程会阻塞,当计数器的值变为 0 时,因 await 方法阻塞的线程会被唤醒,继续执行
2.CyclicBarrier: 循环栅栏
3.Semaphore: 信号灯

0.5 读写锁

1.JAVA 的并发包提供了读写锁 ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁

0.6 阻塞队列 BlockingQueue

• 当队列中没有数据的情况下,消费者端的所有线程都会被自动阻塞(挂起),
直到有数据放入队列
• 当队列中填满数据的情况下,生产者端的所有线程都会被自动阻塞(挂起),
直到队列中有空的位置,线程被自动唤醒
1. 常用
	ArrayBlockingQueue:基于数组的阻塞队列实现,维护了一个定长数组,以便缓存队列中的数据对象
	LinkedBlockingQueue: 基于链表的阻塞队列,同 ArrayListBlockingQueue 类似,其内部也维持着一
个数据缓冲队列

0.7 Fork/Join

• 它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出

在这里插入图片描述

1. 初始化线程的4中方式

1. 继承Thread
2. 实现Runnable接口
3.实现Callable接口 + FutureTask(可以拿到返回结果,可以处理异常)
4. 线程池
方式1 和方式2 : 主线程无法获取线程运算结果,方式3 主进程可以获取线程运算结果,但是不利于控制服务器中的线程资源,可能导致服务器资源耗尽
方式4.线程池性能稳定,也可以获取执行结果,并捕获异常,但是在业务复杂的情况下,一个异步调用可能会依赖于另一个异步调用的执行结果

1.继承Thread

public class TestThread {
    public static void main(String[] args) {
        System.out.println(" main ... start");
        Thread01 thread = new Thread01();
        thread.start();// 启动线程
        System.out.println(" maind ... end ....");
    }
    public static class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /2;
            System.out.println("运行结果:" + i);
        }
    }
}

2.实现 Runnable 接口

public class TestThread {
    public static void main(String[] args) {
        System.out.println(" main ... start");
        Thread01 thread01 = new Thread01();
        new Thread(thread01).start();// 启动线程
        System.out.println(" maind ... end ....");
    }
    public static class Thread01 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /2;
            System.out.println("运行结果:" + i);
        }
    }
}

3. 实现Callable 接口

public class TestThread {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println(" main ... start");
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread01());
        new Thread(futureTask).start();// 启动线程
        Integer value = futureTask.get();
        System.out.println(" maind ... end ....");
    }
    public static class Thread01 implements Callable<Integer> {
        @Override
        public Integer call() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /2;
            System.out.println("运行结果:" + i);
            return i;
        }
    }
}

4. 线程池

public class TestThread {
    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println(" main ... start");
        //1. 没有返回值
        executorService.execute(new Thread01());
        //2. 可以获取返回值
        Future<Integer> future = executorService.submit(new Thread02());
        Integer i = future.get();
        System.out.println(" maind ... end ...." + i);
    }
    public static class Thread01 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /2;
            System.out.println("运行结果:" + i);
        }
    }
    public static class Thread02 implements Callable<Integer> {
        @Override
        public Integer call() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /2;
            System.out.println("运行结果:" + i);
            return i;
        }
    }
}

2.线程池原理

1.七大参数
	1.corePoolSize[5]:核心线程数【一直存在除非设置(allowCoreThreadTimeOut)】创建好以后就准备就绪的线程数量,就等待来接受异步任务去执行 5个。Thread thread = new Thread(); 有任务过来就 thread.start();
	2.maximumPoolSize[100]:最大线程数量:控制资源
	3.keepAliveTime:存活时间 如果当前的线程数量大于核心core数量。释放空闲的线程(maximumPoolSize - corePoolSize = 95),只要线程空闲大于指定的keepAliveTime
	4.unit:时间单位
	5.BlockingQueue<Runnable> workQueue:阻塞队列,如果任务有很多,就会将目前多的任务放在队列里面,只要有线程空闲,就会去队列里面取出新的任务继续执行
	6.threadFactory:线程的创建工厂
	7.RejectedExecutionHandler handler:如果队列满了。按照我们指定的拒绝策略拒绝执行任务
2.线程池工作顺序
	1)线程池创建,准备好core数量的核心线程,准备接受任务
	2)新的任务进来,用core准备好的空闲线程执行
		1)core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列中获取执行任务
		2)阻塞队列满了。就直接开新线程执行,最大只能开到max指定的数量
		3)max都执行好了,Max-core数量空闲的线程会在keepAliveTime指定的时间后自动销毁,最终保持core大小
		4)如果线程数开到max数量,还有新的任务进来,就回使用reject指定的拒绝策略进行处理
	3)所有的线程创建都是由指定的factory创建
3.面试:一个线程池,core 7,max 20,queue 50,现在有100并发进来怎么分配
	答: 7个立即执行,50个进入队列,在开13个进行执行,剩下的30个就使用拒绝策略,如果不想抛弃,可以使用CallerRunsPolicy
4.常见的线程池
	1):newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
	2):newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
	3):创建一个定长线程池,支持定时及周期性任务执行
	4):创建一个单线程化的线程池,只会用唯一的工作线程来执行任务,保证所有任务
5. 线程池优点
	1.降低资源的消耗,通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
	2.提高响应速度
	3.提高线程的可管理性
1.
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
// 1.可缓存
ExecutorService executorService1 = Executors.newCachedThreadPool();
// 2.固定大小 core=max,都不可回收
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
// 3.定时任务
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
// 4.单线程
ExecutorService executorService4 = Executors.newSingleThreadExecutor();

3.异步编排 Completablefuture

1. thenRun: 不能获取到上一步的执行结果
2.thenAcceptAsyn: 能接受上一步结果,但是无返回结果
3.thenApplyAsyn: 能接受上一步结果,有返回值
public class TestThread {
    // 创建线程池
    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main....start");
        // 1.不需要返回值
        CompletableFuture.runAsync(() ->{
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /2;
            System.out.println("运行结果:" + i);
        },executorService);
        // 2,有返回值
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() ->{
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /2;
            System.out.println("运行结果:" + i);
            return i;
        },executorService);
        Integer i = future.get();
        System.out.println("运行结果:" + i);
        // 3.方法执行完后感知
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() ->{
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /0;
            System.out.println("运行结果:" + i);
            return i;
        },executorService).whenComplete((result,excption) ->{
            // 虽然能得到异常信息,但是没法修改返回数据
            System.out.println("异步成功后完成了。。。结果是: " + result + "异常是: " + excption);
        }).exceptionally(throwable -> {
            // 可以感知异常,并修改返回结果
            return 10;
        });
        // 3.方法执行完后处理
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() ->{
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 /4;
            System.out.println("运行结果:" + i);
            return i;
        },executorService).handle((result,excption) ->{
            if(result != null){
                return  result * 2;
            }
            if(excption != null){
                return 0;
            }
            return 0;
        });
        System.out.println("main....end   " + i);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值