1 volatile 关键字
线程可见性、不保证原子性、禁止指令重排序
使用场景要求:对变量的写操作不依赖于当前值,该变量没有包含在具有其它变量的不定式中
使用场景:单例模式,Spring的bean,数据库连接池,线程池
- JMM Java内存模型
2 AtomicInteger
AtomicInteger 支持原子性,unsafe cas自旋(获取当前对象和内存地址,和预期值比较并交换)cas是一条cpu并发原语,执行过程中不允许被中断,是一个原子指令
AtomicInteger–Cas–unsafe–cas底层思想–ABA–原子引用更新–解决ABA问题
3 cas 比较并交换 乐观锁机制
适用于线程冲突少情况,
问题:
- ABA问题,如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。在变量前面加版本号来解决如 1A 2B 3A
- 循环时间长开销大,自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。
- 只能保证一个共享变量的原子操作
4 集合
ConcurrentModificationException,集合高并发下异常,原因:并发争抢导致
解决:
- Collections.synchronizedList();
- Vector();
- CopyOnWriteArrayList(); 写时复制
hashMap和ConcurrentHashMap 区别
5 锁
公平锁,非公平锁,可重入锁(递归锁),自旋锁(循环方式尝试获取锁)手写 AtomicReference,读写锁(ReentrantReadWriteLock)
synchronized 和 lock
1 原始构成:synchronized 底层通过monitorenter(monitor对象完成的,wait和notify也依赖于monitor对象) monitorexit
2 使用方法:synchronized不需要手动释放锁,lock需要
3 是否可以中断:synchronized 不可以,lock可以中断
4 加锁是否公平:synchronized非公平锁,lock可以设置公平
5 锁绑定多个condition lock可精确唤醒某个线程
// 自旋锁 AtomicReference<Thread>
class TestCASLock{
AtomicReference atomicReference = new AtomicReference<>();
public void mylock(){
System.out.println(Thread.currentThread().getName() );
while (!atomicReference.compareAndSet(null,Thread.currentThread())){
}
}
public void myunlock(){
atomicReference.compareAndSet(Thread.currentThread(),null);
}
public static void main(String[] args) {
TestCASLock testAQS = new TestCASLock();
new Thread(()->{
testAQS.mylock();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
testAQS.myunlock();
System.out.println(Thread.currentThread().getName() + " " + "释放");
},"AA").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
testAQS.mylock();
testAQS.myunlock();
System.out.println(Thread.currentThread().getName() + " " + "释放");
},"BB").start();
}
}
读写锁(ReentrantReadWriteLock)
写操作,独占+原子性,整个过程必须是一个完整的整体
// 读写锁
class ReadAndWriteLock{
private volatile Map map = new HashMap<String,Object>();
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void myReadlock(String key){
lock.readLock().lock();
try {
// 开始读
System.out.println("开始读====" + Thread.currentThread().getName());
TimeUnit.MILLISECONDS.sleep(300);
Object o = map.get(map);
// 读完成
System.out.println("读完成====" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
public void myWritelock(String key ,Object value){
lock.writeLock().lock();
try {
// 开始写
System.out.println("开始写====" + Thread.currentThread().getName());
TimeUnit.MILLISECONDS.sleep(300);
map.put(key,value);
// 写完成
System.out.println("写完成====" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
public static void main(String[] args) {
ReadAndWriteLock readAndWriteLock = new ReadAndWriteLock();
for (int i = 0; i < 5; i++) {
final int t = i;
new Thread(()->{
readAndWriteLock.myWritelock("" + t,"xxx");
},i+"").start();
}
for (int i = 0; i < 5; i++) {
final int t = i;
new Thread(()->{
readAndWriteLock.myReadlock(""+t);
},i+"").start();
}
}
}
CountDownLatch 计数器(秦灭六国,一统华夏)
countDownLatch.countDown();
countDownLatch.await();
// CountDownLatch 应用
class CountDownLatchTest{
static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i < 3; i++) {
final int t = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+" 被灭国");
countDownLatch.countDown();
},CountryEnum.getCountryEnum(t).getMsg()).start();
}
countDownLatch.await();
System.out.println("=====");
}
}
// 枚举应用
enum CountryEnum{
ONE(1,"齐"),TWO(2,"楚");
private Integer code;
private String msg;
CountryEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public static CountryEnum getCountryEnum(int c){
CountryEnum[] values = CountryEnum.values();
for (CountryEnum countryEnum : values) {
if (countryEnum.code == c){
return countryEnum;
}
}
return null;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
CyclicBarrier 集齐七龙珠召唤神龙
class CyclicBarrierTest{
static CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("======");
});
public static void main(String[] args) {
for (int i = 1; i < 8; i++) {
final int t = i;
new Thread(()->{
System.out.println("召唤第 "+t+" 龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},i+"").start();
}
}
}
信号量 semaphore 停车位
用于多个共享资源的互斥使用,并发线程数控制
class SemaphoreDemo_test{
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+ " 停车成功");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
System.out.println(Thread.currentThread().getName()+ " 离开停车场");
}
}).start();
}
TimeUnit.SECONDS.sleep(10);
System.out.println("========");
}
}
阻塞队列 BlockingQueue
BlockingQueue 阻塞队列,Collection–Queue–BlockingQueue
方法
add,remove element 抛异常
offer,poll,peek 特殊值(true,null)
put,take 阻塞,超时
用处:生产者消费者模型,线程池,消息中间件
高并发线程操作资源类,判断干活唤醒通知。严防多线程并发下的虚假唤醒
// 生产者消费者 阻塞队列 传统版
class Demo{
private int num = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void add(){
try {
lock.lock();
// 判断
while (0!=num){
// 干活
condition.await();
}
num ++;
System.out.println(Thread.currentThread().getName() + "\t" + num);
condition.signalAll();
}catch (Exception e){
}finally {
lock.unlock();
}
}
public void del(){
try {
lock.lock();
// 判断
while (0 == num){
// 干活
condition.await();
}
num --;
System.out.println(Thread.currentThread().getName() + "\t" + num);
condition.signalAll();
}catch (Exception e){
}finally {
lock.unlock();
}
}
}
class ProductConsimer_tradotionDemo{
// 1 线程 操作 资源类
// 2 判断 干活 通知
// 3 防止虚假唤醒机制 用while
public static void main(String[] args) {
Demo demo = new Demo();
new Thread(()->{
for (int i = 1; i <=5 ; i++) {
demo.add();
}
},"aa").start();
new Thread(()->{
for (int i = 1; i <=5 ; i++) {
demo.del();
}
},"bb").start();
}
}
// 题目 abc三个线程启动 ,a打印5次之后b打印10次之后c打印15次,之后再回到a。
// volatile/cas/atomicInteger/BlockQueue/线程交互
class MyResource{
private volatile boolean FLAG = true;
private AtomicInteger atomicInteger = new AtomicInteger();
BlockingQueue<String> blockingQueue = null;
public MyResource(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
}
public void myProd() throws InterruptedException {
String data;
boolean res ;
while (FLAG){
data = atomicInteger.incrementAndGet()+"";
res = blockingQueue.offer(data,2L,TimeUnit.SECONDS);
if (res){
System.out.println(Thread.currentThread().getName() + "\t" +"插入队列 " + data + "成功");
}else {
System.out.println(Thread.currentThread().getName() + "\t" +"插入队列 " + data + "失败" );
}
TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName() + "\t" +"老板叫停线程,falg = false 生产结束 " );
}
public void myCom() throws InterruptedException {
String data;
while (FLAG){
data = blockingQueue.poll(2L, TimeUnit.SECONDS);
if (data == null || data.equalsIgnoreCase("")){
FLAG = false;
System.out.println(Thread.currentThread().getName() + "\t" +"超时2秒,准备退出 " );
System.out.println();
System.out.println();
return;
}
System.out.println(Thread.currentThread().getName() + "\t" +"消费队列成功 " + data );
}
}
public void stop(){
this.FLAG = false;
}
}
class Testo1{
static MyResource myResource = new MyResource(new ArrayBlockingQueue<>(10));
public static void main(String[] args) {
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "\t" +"生产线程启动 " );
System.out.println();
System.out.println();
try {
myResource.myProd();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"pro").start();
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "\t" +"消费线程启动 " );
System.out.println();
System.out.println();
try {
myResource.myCom();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"com").start();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println();
System.out.println();
System.out.println("5秒中过去了,现在开始停止");
myResource.stop();
}
}
callable
class MyCallable implements Callable{
@Override
public Integer call() throws Exception {
System.out.println("======");
TimeUnit.SECONDS.sleep(3);
return 1024;
}
}
class TestCallable{
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask<>(new MyCallable());
new Thread(futureTask,"aa").start();
System.out.println("main...");
System.out.println(futureTask.get());
}
}
线程池
Executors.newFixedThreadPool(int) 执行长期的任务,性能好
Executors.newSingleThreadPool() 一个任务一个任务执行的场景
Executors.newCachedThreadPool() 执行很多短期异步的小程序
拒绝策略
默认:抛出异常;丢弃等待最久的任务;直接丢弃;既不抛弃也不抛异常
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolProperties pool){
return new ThreadPoolExecutor(pool.getCoreSize(),pool.getMaxSize(),
pool.getKeepAliveTime(), TimeUnit.SECONDS,new LinkedBlockingDeque<>(10000),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
}
最大核心数参数配置:cpu密集型 核数+1;io密集型 核数2倍或者核数/0.1
死锁
JVM
jps -l 查看Java进程号
jstack 进程号查看
1 垃圾回收算法
引用计数法,对象赋值需要维护引用计数器,有一定消耗,较难处理循环引用。已经遗弃
复制算法,复制 清空 互换。没有产生内存碎片,但是浪费空间,大对象复制耗时;新生代
标记清除:没有进行复制,但是产生内存碎片;老年代
标记整理:先标记清除,在进行压缩整理,缺点移动对象的成本;老生代
jvm垃圾回收如何确定垃圾,什么是GC roots?
判断一个对象是否可以被回收:
1 引用计数法:引用加一,失去引用减一,当为零时候就可以被回收。不能解决循环引用。
**2 根搜索路径法:**通过GC Roots的对象作为起点,向下开始搜索,如果一个对象到GC Roots没有任何的引用链相连接时,说明对象不可达。
哪些角色可以成为 GC Roots 根:
2 查看jvm系统默认值
-Xms 堆初始大小
-Xmx 堆最大值,和上边设置成一样
-Xss 初始栈空间
1 JVM 参数类型
-
标配参数 -vesion
-
x参数 -Xmixed 混合模式
-
xx参数
-
Boolean 类型
例:-XX:+PrintGCDetails 是否打印GC收集细节
jps -l 获得进程编号;jinfo -flag PrintGCDetails 13632 (查看jvm参数是否开启,结果+代表开启PrintGCDetail)
-
kv设值类型
例:-XX:MetaspaceSize=128m 设置元空间大小;-XX:MaxTenuringThreshold=15 经过15次进入老年代
-Xms == -XX:InitialHeapSize
-Xmx == -XX:MaxHeapSize
-
查看JVM初始参数 java -XX:+PrintFlagsInitial
查看最终修改参数 java -XX:+PrintFlagsFinal -version : =是人为修改或加载时候修改过的
直接修改参数 java -XX:+PrintFlagsFinal -XX:MetaspaceSize=512m HelloWorld
查看GC垃圾回收器 java -XX:+PrintCommandLineFlags -version
常用JVM参数
-Xms 初始内存大小 1/64
-Xmx 最大内存大小 1/4 默认
-Xss 设置单个线程栈的大小,一般512k到1024k,等价于 -XX:ThreadStackSize
-Xmn 设置年轻代大小
-XX:MetaspaceSize 设置元空间大小,和永久代类似, 元空间使用本地内存,配置1024m
-XX:PrintGCDetails 输出GC日志信息
-XX:SurvivorRatio 设置新生代中eden和s0/s1空间比例,默认8:1:1,=4就是4:1:1
-XX:NewRatio 值就是老年代的占比,年轻代默认1,默认2:1
-XX:MaxTenuringThreshold 设置垃圾最大年龄能进入老年代 0-15之间
示例:-Xms128m -Xmx4096m -Xss1024k -XX:MetaspaceSize=512m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGc
GC
Full GC
四大引用:
强引用:Reference 就算出现了oom也不会对该对象进行垃圾回收
软引用:SoftReference 内存足够时候不回收,内存不够时候回收
弱引用:WeakReference 只要GC就回收
虚引用