java多线程-Thead线程学习记录笔记
Posted YX_blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java多线程-Thead线程学习记录笔记相关的知识,希望对你有一定的参考价值。
介绍的内容:
主要介绍多线程的基本概念到后面的基本使用。以及一些稍微的原理猜测。个人笔记,不喜勿喷
目录
目录
一、线程使用
线程:主要是异步+并行,为了合理的利用cpu资源
一般多线程都会和并发、并行联系在一起。
1.1 概念
并发:单个时间内,能支持的吞吐量。一定需要多线程的参与, 常见的评判指标有:QPS,TPS来进行评判标准
并行:同一时刻能够运行多个任务
1.2 线程生命周期
图:
- 新建NEW、
- 运行RUNNABLE(就绪-->通过cpu调用算法)
- 阻塞BLOCKED、
- 等待WAITING、
- 超时等待TIMED_WAITING、
- 终止 TERMINATED
1.3 java中实现的方式
1.3.1 继承线程 Thread
// 方式一 继承线程 Thread
public class ThreadDemoOne extends Thread
@Override
public void run()
System.out.println("继承 Thread ==> 相关业务逻辑");
super.run();
1.3.2 实现接口Runnable (无返回值)
// 方式二 实现接口Runnable (无返回值)
public class ThreadDemoTwo implements Runnable
@Override
public void run()
System.out.println("实现接口Runnable ==>相关业务逻辑");
1.3.3 实现接口Callable (带返回值)
// 方式三 实现接口Callable (带返回值)
public class ThreadDemoThree implements Callable
@Override
public Object call() throws Exception
System.out.println("实现接口Callable ==>相关业务逻辑");
return null;
1.4线程执行的流程
从程序发出指令之后cpu执行的简短流程
图形:
二、多线程带来的安全性问题
特性:原子性、有序性、可见性
原子性:多线程的不确定性,对资源的抢夺是不确定的,比如:多线程count++中
有序性:这个就涉及到指令重排序。涉及到cpu的高速缓存L1 L2、代码的顺序和执行的顺序不一定是一样的。针对一个变量。在cpu中如果需要,可能会优先运行。new Person -->指令分为三步
可见性:a理论上,所有的资源应该是需要从内存中读取,但是由于cpu高速缓存,导致修改之后的数据没有回写给内存。b:指令优化等 volatile 可以处理这种问题。 true -->另开线程 false
三、如何解决安全性问题
3.1 基本概念
针对带来的安全性问题,我们可以采用相关的策略。更多API可以查看 第四点
- 原子性:automicXXX,synchronized,lock
- 有序性: volatile 、lock、BlockingQueue
- 可见性: volatile ,共享变量、final、synchronized
可见性涉及到cpu内部高速缓存,导致内存数据未及时更新。多线程之间数据的不可见性。
volatitle:解决可见性,防止cpu缓存,让缓存失效。
3.2 如何自己实现上锁操作
1.怎么实现一个锁?需要考虑什么问题呢?如下:
1.条件互斥,共享资源(cas)
cas实现
2.等待队列(抢夺资源的线程存放)
BlockingQueue,链表
3.阻塞
sleep/wait/join/park
4.唤醒
notify/notifyall/unpark
四、线程相关使用工具
4.1相关同步API(了解)
线程同步类 CountDownLatch Semaphore CyclicBarrier
并发集合类 ConcurrentHashMap .ConcurrentSkipListMap , CopyOnWriteArrayList ,BlockingQueue
线程池: Executors
锁:StampedLock(1.8引入) ReentrantLock
原子操作:LongAdder (1.8引入,比AtomicLong 好)
// 实现runnable,或者继承Thread ,返回异常给调用方捕捉。如果实现(Callable接口可以返回参数就不用了)
Thread.currentThread().setUncaughtExceptionHandler();
4.2线程池相关的知识点(掌握)
线程使应用能够更加充分合理地协调利用CPU 、内存、网络、1/0 等系统资源。线程的创建需要开辟虚拟机栈、本地方法枝、程序计数器等线程私有的内存空间。在线程销毁时需要回收这些系统资源。频繁地创建和销毁线程会浪费大量的系统资源,增加并发编程风险。另外,在服务器负载过大的时候,如何让新的线程等待或者友好地拒绝服务?这些都是线程自身无法解决的。所以需要通过线程池协调多个线程, 并实现类似主次线程隔离、定时执行、周期执行等任务。
4.2.1 ThreadPoolExecutor相关参数
corePoolSize:常驻核心数。不会销毁的线程
maximumPool:线程池能够容纳同时执行的最大线程数
keepAliveTime:线程池中的线程空闲时间,当空闲时间达到keepAliveTime 值时,线程会被销毁
TimeUnit:keepAliveTime的时间单位通常是TimeUnit.SECONDS 。
workQueue:缓存队列。当请求数大于线程池能够容纳同时执行的最大线程数时。进入缓存队列
ThreadFactory:线程工厂,分组名称。方便后期出问题时精确定位
handler:执行拒绝策晤的对象。当缓存队列达到上限时,开始执行拒绝策略 RejectedExecutionHandler
4.2.2 线程池提供静态创建
//创建持有足够线程的线程池支持给定的并行度, 并通过使用多个队列减少竞争
Executors.newWorkStealingPool
//maximumPoolSize 最大可以至Integer. MAX_VALUE, 是高度可伸缩的线程池,
Executors.newCachedThreadPool
//最大卫Integer.max_value 不回收线程相比Timer , Schedu l edExecutorService 更安全,
功能更强大, 与newCachedThreadPool 的区别是不回收工作线程。
Executors.newScheduledThreadPool
//建个单线程的线程池,相当于单线程串行执行所有任务, 保证接任务的提交顺序依次执行。
Executors.newSingleThreadExecutor
//输入的参数即是固定线程数,既是核心线程
数也是最大线程数, 不存在空闲线程,所以keepAliveTime 等于O
Executors.newFixedThreadPool
4.2.3猜想一下线程池的实现原理
我们是不是可以自己弄呢?
1.明确为何需要线程池?
池化技术,防止高并发时,资源上面的耗尽和重复创建。限流保护机制
2. 线程池的如何设计呢?
线程执行时,run方法完成就会结束,如何创建线程不销毁呢?
- 1.死循环
- 2 不能无限循环。需要阻塞
- 3 保证有任务就执行,没有任务就阻塞
基本上就是按着这个进行的
4.2.4其他
第一题 问:如何实现一个订阅发布呢?
答:阻塞队列,原理:notify/wait
第二题:怎么算是线程执行完成呢?
答:run 方法运行完成
第三:线程的状态有几种。两种等待的区别
答:共六种, new ,runabled,waitting ,TIMED_WAITING.block ,terminated. ==> waitting 需要唤醒,属于被动唤醒,TIMED_WAITING超时等待==>约定时间之后,自己会自动唤醒,属于主动唤醒
第四:什么是可重入锁
答:就是方法调用方法,递归,可以共用同一把锁,不会发生死锁,ReentrantLock 和synchronized 都属于可重入锁
第五:synchronized 和 ReentrantLock 的区别
答:
都属于可重入锁。
- 特性==>
- synchronized 非公共锁 , ReentrantLock 支持fair and no fair
- synchronized 被动释放锁 ,ReentrantLock 主动释放锁
synchronized 属于关键字, ReentrantLock 属于对象。
以上是关于java多线程-Thead线程学习记录笔记的主要内容,如果未能解决你的问题,请参考以下文章