ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

多线程案例

多线程案例 1.单例模式简介保证创建的类中只有一个实例1.1饿汉模式在类加载的时候就创立实例优点写法简单类加载就完成实例化天然线程安全。缺点类加载就创建对象如果从来不用这个对象会造成内存浪费没有懒加载。1.2懒汉模式用到的时候才创建对象懒加载多线程会创建多个实例优点类加载的时候不会创建对象只有调用getInstance()的时候才去创建实例。如果全程不使用这个单例对象就不会被创建节省内存。缺点线程不安全1.3解决懒汉模式线程不安全方法双层if代码示例1外层第一个 ifif(instance null)作用避免每次都进入锁提升性能如果没有外层 if每次调用 getInstance 都要抢锁退化成性能很差的同步方法懒汉。2内层第二个 ifif(instance null)作用防止多个线程等待锁之后重复创建对象举例线程 A、B 同时通过外层if(instancenull)都判定为 null。A 抢到锁进入同步块B 卡在锁外面等待。A 创建完对象释放锁。B 拿到锁如果没有内层 ifB 直接继续 new又创建一个新对象破坏单例。内层第二次判空就是为了解决这个场景 B 拿到锁之后再检查一次 instance 是否为 null发现已经被 A 创建好了就不再 new。3instance new SingletonLazy()三步首先分配内存构造方法初始化对象instance 引用指向内存地址这里必须给instance加volatile禁止指令重排序。 如果不加 volatile重排序会变成 1‑3‑2线程拿到半初始化对象。2.堵塞队列2.1概念阻塞队列是队列 线程阻塞等待。当队列满往队列放元素的线程会阻塞等待 当队列空从队列取元素的线程会阻塞等待。Java标准库提供了堵塞队列BlockingQueue是一个接口真正实现的类是LinkedBlockingQueue.put方法用于堵塞队列的入队列take方法用于堵塞队列的出队列BlockingQueue也有offer,poll,peek等⽅法,但是这些⽅法不带有阻塞特性.自己实现的堵塞队列环形队列2.2生产者消费模型生产者线程负责生产数据把数据放入换成区堵塞队列消费者线程负责从缓冲区取出数据作用1解耦合生产者和消费者代码、线程互相不直接调用中间依靠缓冲区交互。一方代码修改不会直接影响另一方降低耦合。2削峰填谷生产者、消费者处理速度不一样。生产者生产快消费者处理慢数据先存到缓冲区生产者不会被迫停下来等消费者。突发大量任务过来缓冲区可以 “缓存流量”避免瞬间请求压垮消费者。类似水库洪水来了先存水库下游慢慢放水抵御流量高峰。当枯水期时存放的水可慢慢排放代码示例输出3.线程池为什么要使用线程池时间大量创建、销毁进程系统开销很高-引进了多线程创建、切换、销毁开销比进程小很多。新问题服务器请求量越来越大如果每来一个请求就new Thread()用完就销毁。频繁创建销毁线程依然会带来不小开销。解决方法就是引入线程池提前把一批线程创建好放在池子里保持有任务了直接从池子里拿现成的线程干活任务执行完不会销毁归还到池子里复用省去反复向操作系统申请创建线程开销速度更快3.1核心类ThreadPoolExecutor参数理解1corePoolSize 核心线程数只要不关闭线程池这些线程一直存活。核心线程线程池一开始就已经创立的非核心线程后续线程池发现任务太多而额外创立的2maximumPoolSize 最大线程数核心不够 队列满了才新建非核心线程最多到这个数。最大线程数 核心线程 非核心线程3keepAliveTime非核心线程空闲多久就被销毁。4workQueue 阻塞队列任务来了核心线程忙任务就放到队列排队。5threadFactory创建线程的⼯⼚,参与具体的创建线程⼯作.通过不同线程⼯⼚创建出的线程相当于 对⼀些属性进⾏了不同的初始化设置6handler 拒绝策略队列满、线程数到达最大值新任务来了怎么处理。四种拒绝策略3.2实现线程池测试输出结果可以看到创建的四条线程在反复执行着1000个任务4.定时器概念定时器就相当于是闹钟时间一到就执行设定好的任务Java提供了Timer类核心方法为schedule以下是自己实现的定时器
返回列表