是指从软件或者硬件上实现多个线程并发执行的技术
进程:是正在运行的软件
线程:是进程中的单个顺序控制流,是一条执行路径。软件程序中做的事情
方案1:继承Thread类
定义一个类MyThread继承Thread类
在MyThread类中重写run()方法
创建MyThread类的对象
启动线程
run():封装线程执行的代码,直接调用,相当于普通方法的调用,并没有开启线程。
start():启动线程;然后由JVM调用此线程的run()方法
方式2:实现Runnable接口
方式3:Callable和Future
实现Runnable、Callable接口
继承Thread类
获取线程的名字
Thread类中设置线程的名字
获得当前线程的对象
线程休眠
线程调度
多线程的并发运行:计算机中的CPU,在任意时刻只能执行一条机器指令。每个线程只有获得CPU的使用权才能执行代码。各个线程轮流获得CPU的使用权,分别执行各自的任务。
线程有两种调度模型
线程的优先级
后台线程/守护线程
线程生命周期
同步代码块:锁多条语句操作共享数据,可以使用同步代码块实现
同步的好处和弊端
同步方法:就是把synchronized关键字加到方法上
同步代码块和同步方法的区别:
同步方法的锁对象是什么呢?
同步静态方法:就是把synchronized关键字加到静态方法上
同步静态方法的锁对象是什么呢?
Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了获得锁和释放锁的方法
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock的构造方法
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。
等待和唤醒的方法
void wait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
void notify() 唤醒正在等待对象监视器的单个线程
void notifyAll() 唤醒正在等待对象监视器的所有线程
阻塞队列实现等待唤醒机制
BlockingQueue的核心方法:
常见BlockingQueue:
阻塞队列继承结构
多线程的弊端:用到线程的时候就创建,用完之后线程消失。
创建线程池对象
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);
参数一:核心线程数量.不能小于0
参数二:最大线程数.不能小于等于0,最大数量 >= 核心线程数量
参数三:空闲线程最大存活时间.不能小于0
参数四:时间单位.时间单位
参数五:任务队列.不能为null
参数六:创建线程工厂.不能为null
参数七:任务的拒绝策略.不能为null
任务拒绝策略
ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。是默认的策略。
ThreadPoolExecutor.DiscardPolicy: 丢弃任务,但是不抛出异常 这是不推荐的做法。
ThreadPoolExecutor.DiscardOldestPolicy: 抛弃队列中等待最久的任务 然后把当前任务加入队列中。
ThreadPoolExecutor.CallerRunsPolicy: 调用任务的run()方法绕过线程池直接执行。
Volatile关键字:强制线程每次在使用的时候,都会看一下共享区域最新的值
Synchronized同步代码块
所谓的原子性是指在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可以分割的整体。
volatile关键字:只能保证线程每次在使用共享数据的时候是最新值。但是不能保证原子性。
原子类AtomicInteger
public AtomicInteger(): 初始化一个默认值为0的原子型Integer
public AtomicInteger(int initialValue): 初始化一个指定值的原子型Integer
int get(): 获取值int
getAndIncrement(): 以原子方式将当前值加1,注意,这里返回的是自增前的值。
int incrementAndGet(): 以原子方式将当前值加1,注意,这里返回的是自增后的值。
int addAndGet(int data): 以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。
int getAndSet(int value): 以原子方式设置为newValue的值,并返回旧值。
AtomicInteger原理
自旋锁 + CAS 算法
CAS算法:
自旋+CAS
CAS 算法:
synchronized和CAS的区别
相同点:在多线程情况下,都可以保证共享数据的安全性。
不同点:synchronized总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改。所以在每次操作共享数据之前,都会上锁。(悲观锁)
cas是从乐观的角度出发,假设每次获取数据别人都不会修改,所以不会上锁。只不过在修改共享数据的时候,会检查一下,别人有没有修改过这个数据。如果别人修改过,那么我再次获取现在最新的值。如果别人没有修改过,那么我现在直接修改共享数据的值。(乐观锁)
Hashtable
ConcurrentHashMap
ConcurrentHashMap1.7版本原理解析
ConcurrentHashMap1.8版本原理解析
底层结构:哈希表。(数组、链表、红黑树的结合体)。
结合CAS机制 + synchronized同步代码块形式保证线程安全。
CountDownLatch
让某一条线程等待其他线程执行完毕之后再执行。
public CountDownLatch(int count) 参数传递线程数,表示等待线程数量
public void await() 让线程等待
public void countDown() 当前线程执行完毕
Semaphore
可以控制访问特定资源的线程数量。