美文网首页
Java面试——多线程与并发

Java面试——多线程与并发

作者: 抬头挺胸才算活着 | 来源:发表于2020-03-12 11:50 被阅读0次

    CAS的原理

    AQS等待队列为什么设计成双向链表?

    juc包下知道哪些类?

    AQS,ReentrantLock,ReentrantReadWriteLock,Semaphore,CountdownLatch,ConcurrentHashMap,CopyOnWriteArrayList


    线程的sleep()方法和yield()方法有什么区别?

    ①sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
    ② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
    ③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
    ④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

    线程的基本状态以及状态之间的关系

    注意阻塞跟等待,在Sychronize中就有阻塞跟等待,等待锁的时候是阻塞,调用wait的时候是等待。

    1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。

    2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
      线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。

    3. 阻塞(BLOCKED):表示线程阻塞于锁。

    4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

    5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。

    6. 终止(TERMINATED):表示该线程已经执行完毕。


    7. 在 java 程序中怎么保证多线程的运行安全?
      线程安全在三个方面体现:
      原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
      可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
      有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。

    8. 多线程锁的升级原理是什么?
      在Java中,锁共有4种状态,级别从低到高依次为:无状态锁,偏向锁,轻量级锁和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。
      锁升级的图示过程:


      图片.png

    交替输出

    三个线程分别输出'a','l','i',输出'a'的线程控制输出的次数。

    public class main {
        private volatile static boolean hasAPrint = false;
        private volatile static boolean hasLPrint = true;
        private volatile static boolean hasIPrint = true;
    
        public static void main(String[] args) {
    
            Object lock = new Object();
    
            new Thread(()->{
                for(int i=0;i<5;i++) {
                    synchronized (lock) {
                        while (!hasIPrint) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.print("a");
                        hasAPrint = true;
                        hasIPrint = false;
                        lock.notifyAll();
                    }
                }
            }).start();
    
            new Thread(()->{
                while (true) {
                    synchronized (lock) {
                        while (!hasAPrint) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.print("l");
                        hasLPrint = true;
                        hasAPrint = false;
                        lock.notifyAll();
                    }
                }
    
            }).start();
    
            new Thread(()->{
                while (true) {
                    synchronized (lock) {
                        while (!hasLPrint) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.print("i");
                        hasIPrint = true;
                        hasLPrint = false;
                        lock.notifyAll();
                    }
                }
            }).start();
    }
    

    大部分的代码都是一样的,下面是精简版本。
    总结来说,这是同步,一个做完另外一个才接着做。

    public class Printer {
        private volatile int times;
        private volatile int completeCondition;
    
        public Printer(int times, int completeCondition) {
            this.times = times;
            this.completeCondition = completeCondition;
        }
    
        public void print(int waitCondition, int completeCondition, String string){
            for (int i = 0; i < times; i++) {
                synchronized (this){
                    while(this.completeCondition!=waitCondition){
                        try {
                            this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(string);
                    this.completeCondition = completeCondition;
                    this.notifyAll();
                }
            }
        }
    
        private volatile static Printer printer = new Printer(5, 0);
    
        public static void testPrint() {
            new Thread(()->{
                printer.print(0, 1, "a");
            }).start();
    
            new Thread(()->{
                printer.print(1, 2, "l");
            }).start();
    
            new Thread(()->{
                printer.print(2, 0, "i");
            }).start();
        }
    }
    
    

    线程池

    对于一个普通的线程池,coreSize = 5, maxSize = 10,阻塞队列长度 20,且插入线程是永久执行的,那么不断插入线程,线程池中的数量以及对应的反应如何?
    注意无法加入队列的时候再创建线程


    相关文章

      网友评论

          本文标题:Java面试——多线程与并发

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