面试二

作者: 我是嘻哈大哥 | 来源:发表于2019-05-19 17:53 被阅读0次

    1.volatile

    轻量级的同步机制
    特性:
    (1)保证可见性     缓存-主存
    (2)不保证原子性   atomic 
    (3)禁止指令重排序 编译器优化程序
    使用场景:单例模式 
    

    2.CAS

    CompareAndSet
    底层原理
    Unsafe类
    

    3.集合不安全

    3.1 ArrayList
    故障:多线程下使用不安全 java.util.ConcurrentModificationException
    导致原因:并发争抢修改导致,参考我们的花名册情况,一个人正在写入,另一个同学过来抢,并发写入异常
    解决方案:

    3.1.1 List<String> list=new Vector<>();
    3.1.2 List<String> list=Collections.synchonizedList(new ArrayList<>());
    3.1.3 List<String> list=new CopyOnWriteArrayList<>();//写时复制 读写分离
    

    3.2 HashSet(底层是HashMap)
    故障:多线程下使用不安全 java.util.ConcurrentModificationException
    解决方案:

    3.2.1 Set<String> set=Collections.synchonizedSet(new HashSet<>());
    3.2.2 Set<String> set=new CopyOnWriteArraySet<>(); //底层还是CopyOnWriteArrayList
    HashSet.add(E);
    ->HashMap.put(E,new Object());//添加的key
    

    3.3 HashMap
    故障:多线程下使用不安全 java.util.ConcurrentModificationException
    解决方案:

    3.2.1 Map<String> map=Collections.synchonizedMap(new HashMap<>());
    3.2.2 Map<String> map=new ConcurrentHashMap<>(); 
    

    4.公平锁/非公平锁、可重入锁、独占锁/共享锁、自旋锁
    公平锁:只多个线程按照申请的顺序来获取锁,类似排队打饭,先来后到
    非公平锁:抢占,优点吞吐量大。ReentrantLock:可以使用构造函数中的boolean类型来获得公平锁或公平锁,默认为非公平锁。对于Synchonized,也是一种非公平锁
    可重入锁(又名递归锁):线程可以进入任何一个它已经拥有锁所同步的代码块。ReentrantLock和Synchonized就是可重入锁,最大作用就是避免死锁
    自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

    public class SpinLock {
        //原子引用线程
        private AtomicReference<Thread> cas = new AtomicReference<Thread>();
        
        public void lock() {
            Thread current = Thread.currentThread();
            // 利用CAS
            while (!cas.compareAndSet(null, current)) {
                // DO nothing
            }
        }
        public void unlock() {
            Thread current = Thread.currentThread();
            cas.compareAndSet(current, null);
        }
    }
    

    5、ReentrantReadWriteLock
    读写锁

    6.CountDownLatch
    减计数,到0时释放锁——秦灭六国,然后一统天下

    7.CycllicBarrier
    增计数,到指定值后释放锁——七龙珠

    8.Semaphore
    多个线程抢占多个资源,可替代synchorized和Lock

    9.阻塞队列
    9.1阻塞队列有没有好的一面
    好处是不需要关心什么时候需要阻塞线程,什么时候需要唤醒
    9.2 核心方法

    >Collection
    >>List
    
    >>Queue
    >>>BlockingQueue
    >>>>ArrayBlockingQueue 数组组成的有界阻塞队列
    >>>>LinkedBlockingQueue 链表组成的有界阻塞队列
    >>>>PriporityBlockingQueue
    >>>>DealyQueue
    >>>>SynchronousQueue    同步队列,单个元素的队列
    >>>>LinkedTransferQueue 链表组成的无界阻塞队列
    >>>>LinkedBlockingDeque 链表组成的双向阻塞队列
    
    BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(3);
    
    blockingQueue.add("a"); //抛异常
    blockingQueue.element();
    blockingQueue.remove();
    
    blockingQueue.offer("a");//返回true或false
    blockingQueue.peak();
    blockingQueue.poll();
    
    blockingQueue.put("a");//阻塞
    blockingQueue.take();
    
    blockingQueue.offer("a",2L,TimeUnit.SECOND);//过时不候
    

    //生产者消费者案例

    线程 操作 资源类
    判断 干活 通知
    防止虚假唤醒

    //传统版

    class ShareData{
        private int number=0;
        private Lock=new ReentrantLock();
        private Condition condition=lock.newCondition();
        
        public void increment() throw Execption{
            Lock.lock();
            try{
               //判断
               while(number!=0){
                  //等待,不能生产
                  condition.await();
               }
               //干活
               number++;
               
               //通知唤醒
               condition.singalAll();       
            }
            catch(Execption e){
                e.printStackTrace();
            }
            finally{
                Lock.unlock();
            }
        }
        
        public void decrement() throw Execption{
            Lock.lock();
            try{
               //判断
               while(number==0){
                  //等待,不能生产
                  condition.await();
               }
               //干活
               number--;
               
               //通知唤醒
               condition.singalAll();       
            }
            catch(Execption e){
               e.printStackTrace();
            }
            finally{
                Lock.unlock();
            }
        }
    }
    

    synchonized和lock区别
    (1)synchonized 关键字 底层是monitor(monitorenter、monitorexit-正常和异常退出)实现,lock是具体的类
    (2)使用方法,synchonized自动释放,lock是手动释放
    (3)等待是否可中断。synchonized不可中断,lock可以中断
    (4)加锁是否公平。synchonized非公平锁,lock可以设置,默认是非公平
    (5)锁绑定多个condition

    class ShareData{
        private int number=1;
        private Lock lock=new ReentrantLock();
        private Condition c1=lock.newCondition();
        private Condition c2=lock.newCondition();
        private Condition c3=lock.newCondition();
        
        public void print5(){
                Lock.lock();
            try{
               
               while(number!=1){
                  
                  c1.await();
               }
               //干活
               
               //通知唤醒c2
               number=2;
               c2.signal();     
            }
            catch(Execption e){
               e.printStackTrace();
            }
            finally{
                Lock.unlock();
            }   
        }
    }
    

    10 线程池
    10.1 七大参数

    ThreadPoolExecutor的7大参数
    corePoolSize      核心线程数                银行今日当值2个窗口
    maximumPoolSize   最大线程数                银行最大5个窗口
    keepAliveTime     多余空闲线程存活时间      扩容后,规定时间内没有多余的请求后,销毁扩容的线程,直到只剩下核心线程
    unit              单位
    workQueue         阻塞队列                  银行候客区
    threadFactory     线程工厂                  用于创建线程的工厂,一般默认即可
    handler           拒绝策略                  有4种
    

    10.2 线程池底层工作原理
    四步工作流程:
    1.少于核心数,直接在核心数执行
    2.大于核心数,多余的进入阻塞队列
    3.大于阻塞队列,开启扩容到最大线程数
    4.还再加大,开启拒绝策略
    5.扩容区空闲超出空闲时间,释放扩容区。

    10.3 拒绝策略RejectedExecutionHandler

    AbortPolicy            直接抛出异常
    CallerPolicy           回退任务到调用者
    DiscardOldestPolicy    丢弃等待时间最长的
    DiscardPolicy          直接丢弃
    

    10.4 工作中用到的线程池
    常用的三个(newSingle newFixed newCache)一个都不用? 有可能导致OOM

    10.5 自定义线程池编写

    ExectorService threadPool=new ThreadPoolExecutor(2,
                                                     5,
                                                     1L                                              TimeUnit.SECOND,
                                                     new LinkedBlockingQueue<Runnable>(3),
                                                     Executors.defaultThreadFactory,
                                                     new ThreadPoolExecutor.AbortPolicy);
    1) AbortPolicy 超出8个后直接抛出异常
    2) CallerPolicy 回退任务到调用者,如main线程启动的线程则回退到main线程
    3) DiscardOldestPolicy 丢弃
    4) DiscardPolicy       丢弃
    

    合理配置线程池线程数:

    1)获取运行服务器的cpu核心数;
    2)CPU密集型:1+cpu核心数
    2)IO密集型:(1)cpu核心数*2 (2)cpu核心数/1-阻塞系数  阻塞系数0.8-0.9
    

    11.死锁编码及定位分析
    两个或两个以上的线程在执行过程中,因争抢资源而出现互相等待

    class HoldLockThread implements Runnable{
       
       private String lockA;
       private String lockB;
       
       public HoldLockThread(String lockA,String lockB){
         This.lockA=lockA;
         This.lockB=lockB;
       }
       
       public void run(){
            synchonized(lockA){
               sout("自己持有A锁,尝试持有B锁");
               synchonized(lockB){
                 sout("自己持有B锁,尝试持有A锁");
               }
            }
       }
    }
    
    new Thread(new HoldLockThread(lockA,lockB)).start();
    new Thread(new HoldLockThread(lockB,lockA)).start();
    

    如何证明出现死锁?

    jps -l 获得进程号
    jstack 9636  Found 1 deadLock
    

    12.JVM
    12.1
    垃圾回收的区域:方法区 堆

    回收算法:

    引用计数
    复制回收
    标记清除
    标记整理
    

    GCRoot
    12.2 JVM参数

    jps -l 查看Java后台进程
    jinfo -flag 具体参数 进程号
    jinfo -flags  进程号
    

    标配参数

    X参数

    XX参数
    1)布尔类型

    公式:+(开启) -(关闭)
    -XX:+PrintGCDetails
    

    2)KV设值型

    -XX:MetaspaceSize=1024m
    -XX:MaxTenuringThreshold=15
    

    坑题:

    -Xms1024m 等价于 -XX:InitialHeapSize
    -Xmx1024m 等价于 -XX:MaxHeapSize
    

    查看参数盘点家底

    java  -XX:+PrintFlagsInitial  =   :=
    

    Java中的几种引用方式

    Java中有几种不同的引用方式,它们分别是:强引用、软引用、弱引用和虚引用。下面,我们首先详细地了解下这几种引用方式的意义。

    强引用

    在此之前我们介绍的内容中所使用的引用 都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。
    当内存空间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
    

    软引用(SoftReference )

    SoftReference 类的一个典型用途就是用于内存敏感的高速缓存。 SoftReference  的原理是:在保持对对象的引用时保证在  JVM  报告内存不足情况之前将清除所有的软引用。
    关键之处在于,垃圾收集器在运行时可能会(也可能不会)释放软可及对象。对象是否被释放取决于垃圾收集器的算法 以及垃圾收集器运行时可用的内存数量。
    

    弱引用(WeakReference )

    WeakReference 类的一个典型用途就是规范化映射( canonicalized mapping )。另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说,弱引用也比较有用。
    关键之处在于,垃圾收集器运行时如果碰到了弱可及对象,将释放  WeakReference  引用的对象。然而,请注意,垃圾收集器可能要运行多次才能找到并释放弱可及对象。
    

    虚引用(PhantomReference )

    PhantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行  pre-mortem  清除操作。 PhantomReference  必须与  ReferenceQueue  类一起使用。
    需要  ReferenceQueue  是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时, PhantomReference  对象就被放在它的  ReferenceQueue  上。
    将  PhantomReference  对象放在  ReferenceQueue  上也就是一个通知,表明  PhantomReference  对象引用的对象已经结束,可供收集了。
    这使您能够刚好在对象占用的内存被回收之前采取行动。 Reference与 ReferenceQueue 的配合使用
    

    如何选择垃圾收集器?

    组合选择
    单cpu或小内存,单机程序
    -XX+UseSericalGC
    多cpu,需要大量吞吐量,如后台计算型应用
    -XX+UseParallelGC或者
    -XX+UseParallelOldGC
    多cpu,追求地停顿时间,需要快速响应互联网应用
    -XX:+UseConcMarkSweepGC
    -XX:+ParNewGC
    

    G1垃圾收集器
    服务端垃圾收集器,应用在多处理器和大量内存环境,在实现高吞吐的同时,还具有以下点:
    与CMS一样,可以高并发执行
    预测GC停顿时间
    不希望牺牲更大的吞吐性能
    不需要更大的java heap

    主要改变是Eden,survivor和tenured等区域不是连续的,而是变成了一个大小一样的region,每个region大小不等,从1M-32M,每一个region有可能属于Eden,survivor和tenured

    底层原理:

    region区域化垃圾收集器  默认拆分2048个分区   
    32M*2048=64G最大内存
    
    //cpu
    top  uptime
    vmstat -n 2 3
    mpstat -P ALL 2
    pidstat -u 1 -p 进程号
    
    //内存
    free -m
    pidstat -p 进程号 -r 间隔时间
    
    //磁盘IO
    df -h  
    iostat -xdk 2 3
    pidstat -d 采样间隔 -p 进程号 
    
    //网络IO
    ifstat 1
    

    生产环境cpu过高怎么办?

    1.先用top找cpu占比最高的;
    2.定位后台那个程序影响到的;
    3.定位到具体线程和代码; ps -mp 进程 -o THREAD,tid,time
    4.将需要的线程id转换成16进制格式
    5.jstack 进程id|grep pid(16进制ID或者小写英文格式) -A60
    

    github骚操作

    in:name              //名字中包含
    in:readme            //readme中包含
    in:despcription      //描述包含
    in:name,readme       //组合使用
    
    springboot stars:>=5000   //点赞数超过5000的spring boot项目
    springcloud forks:>500  //fork数大于500的spring cloud项目
    springboot stars:100..200 forks:100..200 //组合区间查询
    
    awesome redis  //awesome 一般收集、学习相关技术的搜素方法
    
    https://github.com/codingXiaxw/seckill/blob/157ebd15ffce3434d8039670a95a5fe000c0fb97/src/main/java/cn/codingxiaxw/dao/SeckillDao.java#L13 //#L13 高亮显示13行
    https://github.com/codingXiaxw/seckill/blob/157ebd15ffce3434d8039670a95a5fe000c0fb97/src/main/java/cn/codingxiaxw/dao/SeckillDao.java#L13-L23  //#L13-L23  高亮13-23行
    

    t 项目内搜索

    location:beijing language:java  //查找北京java活跃用户
    

    相关文章

      网友评论

          本文标题:面试二

          本文链接:https://www.haomeiwen.com/subject/uypqzqtx.html