目录
解雇摸鱼状态下的正式员工?allowCoreThreadTimeout(...)
1.前置知识
1.锁+volatile(线程安全保护)
保护变量的内存可见性
保证代码重排序
针对long a = ... double a = .... 的时候,可以保护它的原子性
设计模式:对一些解决通用问题的、经常书写的代码片段的总结与归纳
单例模式:通过代码,保护一个类,使得类在整个进程(应用)运行过程中有且只有一个对象
饿汉模式:一开始就初始化
懒汉模式:等用到的时候才开始初始化
2.线程通知(wait-notify)
线程和线程之间需要相互等待、通知
1.wait()和notify()方法是属于Object类的,Java中的对象都带有这两个方法
2.要使用wait和notify,必须首先对“对象”进行sunchronized加锁
含义:等待-通知
Object.wait();
Object.notify(); 随机唤醒
1.加锁 2.wait的时候会释放锁(只会释放wait这个锁)3.wait的终止条件(被唤醒、被终止、假唤醒) 4.notify唤醒是随机的,notifyAll是全部唤醒 5.先notify后wait没用
3.各种各样的锁
读锁(共享锁)vs 写锁(独占锁)
目前使用的锁都是独占锁(只有一个线程能持有锁)
重入锁 ReentrantLock VS 不可重入锁
最大区别在于:是否可以允许持有锁的线程成功请求到同一把锁
synchronized锁是可重入锁
公平锁fair VS 非公平锁
非公平锁实现简单(默认)
公平:严格按照请求锁的次序获取到锁
synchronized锁是不公平的
juc下的ReentrantLock可以通过传入fair = true/false来控制是否是公平的
乐观锁 VS 悲观锁
翻译的问题:严格来讲,这两个是实现并发控制的两种不同方案,和“锁”的概念都不是一个层级的
乐观锁:评估后,并发情况,多个线程同时修改一个共享资源的情况比价少见,可以采用轻量级(无锁lock -free)方式,进行并发控制。
悲观锁:多个线程会频繁的修改同一个共享资源,必须使用互斥的方式(锁lock)来进行并发控制
4.锁的实现导致锁的种类
默认情况下,我们锁的实现,是采用OS提供的锁(mutex锁:互斥锁)
一旦请求锁失败,会导致当前线程(请求锁失败的线程)会放弃CPU,进入阻塞状态,把自己加到锁的阻塞队列中,等待被唤醒。
实现角度:互斥锁mutex VS 自旋锁spin lock
synchronized锁的实现和优化:
策略:可重入的+不公平的+独占锁
实现:
1.锁消除优化
Vector v = new Vector(); v...
前提:Vector为了做到线程安全,每个方法都使用synchronized修饰了
实际上,代码中只有主线程 -> 所有线程保护的操作都是无用功(加锁、释放锁)
编译器+JVM判断出只有一个线程时,就会消除所有锁的操作,来提升性能
2.锁的粗化优化
前提:已经没办法进行锁消除的情况
2.阻塞队列 blocking queue(FIFO)
1.blockingQueue具体方法
put(e) 结束 队列中有位置了,放入元素
当有人让线程结束时,放入失败,也会结束,以InterruptedException形式体现
take() throw InterruptedException
poll(time,unit) throw InterruptedException
offer(e,time,unit) throw InterruptedException
生成-消费者模型:
一个(多个线程)只负责向队列放入元素
一个(多个线程)负责从队列中取出元素
2.定时器
1.Timer类——任务调度(闹钟)
继承TimerTask类,重写run方法,指定要执行的任务
定时器执行任务时,不会占用我们的当前执行流
2.Timer实现方式:
一个延时任务需要创建一个线程
java中的Timer实现方式:一个任务,执行多个任务
3.sleep()和wait(timeout)的区别
a.语义不同:休眠/等待
b.sleep一定休眠固定时间的 wait(timeout)有两个结束条件:超时时间已到、条件满足
c.Thread静态方法 /Object的普通方法
d.sleep和锁没有关系 wait会释放当前对象的锁
3.线程池Thread pool
矛盾:创建/销毁线程都是有成本的
有新的任务 ->创建新线程(无意义成本)->执行任务->销毁线程(无意义成本)
解雇摸鱼状态下的正式员工?allowCoreThreadTimeout(...)
corePoolSize:全部的线程上限
maximumPoolSize:全部的线程上限
keepAliveTime+unit:默认情况下>corePoolSize的线程的存活时间(没有任务时)
queue:任务队列
rejectHandle:拒绝(默认)、调用者允许、丢弃最老的、丢弃当前
按需创建:
1.一开始一个线程都没有,随着任务提交,创建core线程(当前线程数<corePoolSize)
2.优先提交队列,直到队列满
3.创建>corePoolSize的线程,直到maximumPoolSize
4.执行拒绝策略
3.多线程:并发编程总结
1.语法+OJ(数据结构+编程能力) 5
2.数据库的使用 4
3.多线程 3
(1)理论 2
a. 实际中+面试都重要的
1.计组+OS的基本知识
2.啥是多线程 ,什么是调度
3.多线程的不确定性
4.线程的状态
5.数据的共享、JVM运行时内存区域划分+那些区域是共享的
6.什么是线程安全
7.两个角度理解线程安全:
1.共享&&写的操作
2.原子性、内存可见性、代码重排序
8.JMM:java内存模型(工作内存+主内存)
9.happen-before
10.锁的理论(synchronized的使用和互斥)
11.volatile的理解
12.wait-notify
b. 只是面试中可能押题用的(锦上添花)
1.锁的策略
2.synchronized的优化
3.ConcurrentHashMap(HashMao)基本知识
(2)代码的编写 1
原则:线程的视角,不要以类、方法为视角。
类、对象、方法,完全可以被多个线程调用
单例模式
阻塞队列、定时器、线程池
juc下的其他类