Java线程及线程池
什么是线程安全
- 多个任务同时运行,不会出问题
- 类的全局变量和静态变量在多个线程同时访问时,如果只有读为线程安全,如果有写,则可能出现线程不安全
创建线程的3种方式
- 继承Thread类,并重写run()方法
- 实现Runnable接口,并实现run()方法
- 实现Callable接口,有返回值
Runnable接口和Callable接口的区别
一个有返回值,一个没有
wait方法和sleep方法的区别
wait会让出线程锁,让别的线程先执行,sleep不会
介绍下CAS(无锁技术),什么是悲观锁和乐观锁
- CAS是CPU的指令,将比较和转换做为一个原子操作,如果比较的结果是预期结果就是转换,否则不做任何操作。但是,这会出现另一个问题:ABA,即会出现在CAS执行时,虽然比较结果是成功的,但不知道这个结果是否已经被改过新值又改回原值,故可以用AtomicStampedReference,在初始化时添加一个版本号,比较时也比较版本号来保证没有被修改过
- 悲观锁:synchronized锁,即在执行多线程代码时,会出现竞争问题,先给这段代码上锁
- 乐观锁:CAS锁,操作为原子性,如果失败,通过死循环来重复执行,直到成功达到预期
volatile关键字的作用和原理
volatile是轻量级的同步锁,但不是原子性的,因为这个关键字是在主内存中,每个得到锁的线程在运行时,会先从主内存中把这个值放到自己的线程工作内存中,因此会出现不准确的同步。同时,这个关键字也会防止指令重排,保证化修饰的变量不会出现指令重排。
什么是ThreadLocal
- ThreadLocal是Thread中的一个变量,可以叫做线程本地变量,用来保存线程中的一个对象,如在多线程环境中,每个线程有session、connection等,只要有任务过来,就可以立即用自己线程ThreadLoacl中的保存的对象进行操作,不必从主线程或者主内存中取数据,即中空间换取时间,来提高运行速度。
- 在保存ThreadLoacl中使用的是类似HashMap的一个ThreadLocalMap,对线程隔离后,每个线程保存对象的一个线程私有变量。
创建线程池的4种方式
- Executors.newCachedThreadPool():缓存线程池,没有初始数,最大为Integer.MAX
- Executors.newFixedThreadPool(2):固定数线程池,初始值即为最大值,有一个链表队列
- Executors.newSingleThreadExecutor():单线程池,有一个链表队列
- Executors.newWorkStealingPool():
线程池启动的参数解释
new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
- 初始个数:线程池中的初始线程个数,必须大于0
- 最大个数:线程池中的最大线程个数,不能小于初始线程个数
- 存活时间:超过初始线程数后的那些线程存活时间
- 时间单位:3的时间单位
- 任务队列:当线程池中的个数为最大线程数时,新来的任务将放到该队列中
- 线程工厂:用来启动线程,自定义线程名字等
- 满队策略:当队列满后,执行的异常策略
任务队列:
- ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,按FIFO原则进行排序
- LinkedBlockingQueue:一个基于链表结构的阻塞队列,吞吐量高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
- SynchronousQueue: 一个不存储元素的阻塞队列。每个插入操作必须等另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool()使用了这个队列
- PriorityBlockingQueue:一个具有优先级的无限阻塞队列。