面试第二季

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 进程号查看

image-20210303215138835

1 垃圾回收算法

引用计数法,对象赋值需要维护引用计数器,有一定消耗,较难处理循环引用。已经遗弃

复制算法,复制 清空 互换。没有产生内存碎片,但是浪费空间,大对象复制耗时;新生代

标记清除:没有进行复制,但是产生内存碎片;老年代

标记整理:先标记清除,在进行压缩整理,缺点移动对象的成本;老生代

jvm垃圾回收如何确定垃圾,什么是GC roots?

判断一个对象是否可以被回收:

1 引用计数法:引用加一,失去引用减一,当为零时候就可以被回收。不能解决循环引用。

**2 根搜索路径法:**通过GC Roots的对象作为起点,向下开始搜索,如果一个对象到GC Roots没有任何的引用链相连接时,说明对象不可达。

哪些角色可以成为 GC Roots 根:

image-20210303221431795

image-20210303221650027


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

image-20210304211447841

Full GC

image-20210304211411801

四大引用:

强引用:Reference 就算出现了oom也不会对该对象进行垃圾回收

软引用:SoftReference 内存足够时候不回收,内存不够时候回收

弱引用:WeakReference 只要GC就回收

虚引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值