美文网首页
多线程TOP50

多线程TOP50

作者: 金馆长说 | 来源:发表于2018-09-19 16:17 被阅读9次

    什么是线程?

    线程是CPU的最小执行单元,当依附在进程之下的。程序就是一个进程,比如windows的.exe程序,或者android系统的一个app就是一个独立的进程,一个进程可以创建多个线程。

    特点

    • 线程拥有自己的计数器、堆栈、局部变量等属性
    • 提高执行效率和用户体验,执行一些耗时的异步任务。

    什么是线程安全和线程不安全?

    • 线程安全
      线程安全就是在多线程下,对数据或者代码进行加锁保护。只有获得锁的线程才能执行代码,没有获得锁的线程会处于堵塞状态,等待释放锁后才能执行。这样做保证了数据在多线程执行下的安全性

    • 线程不安全
      多线程的代码或者数据如果没有使用同步机制,可能会出现数据不能达到预期的结果,出现很多脏数据。

    什么是自旋锁?
    什么是Java内存模型?
    什么是CAS?
    什么是乐观锁和悲观锁?
    什么是AQS?
    什么是原子操作?在Java Concurrency API中有哪些原子类(atomic classes)?
    什么是Executors框架?

    什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型?

    阻塞队列就是在队列的基础上增加了二个操作

      1. 支持阻塞插入方法
        队列满时,插入元素的的线程会阻塞,直到队列不满。
      1. 支持阻塞移除方法
        队列为空时,获取元素的线程处于阻塞等待队列不为空

    生产消费者模式
    这个模式就是运用了以上增加的二个方法,一个线程创建创建队列元素,一个线程消费队列元素。

    class Queque {
    
    
        @Test
        public fun test() {
            var queue = LinkedBlockingQueue<Any>(10)
            Thread(Producer(queue)).start()
    
            Thread(Consumer(queue)).start()
    
    
            Thread.sleep(1000)
    //        System.exit(0)
    
    
        }
    
    
        //生产者
        class Producer(var queue: BlockingQueue<Any>) : Runnable {
    
    
            override fun run() {
                try {
                    while (true) {
                        var any = getObject()
                        queue.put(any)
                        System.out.println("生产者资源队列大小 ${queue.size}")
                    }
                } catch (ex: Exception) {
                    System.out.println("******生产者中断******")
                }
            }
    
            fun getObject(): Any {
                try {
    //                Thread.sleep(1000)
                } catch (ex: Exception) {
                    System.out.println("******生产者创建中断******")
                }
                return Any()
            }
        }
    
    
        //消费者
    
        class Consumer(var queue: BlockingQueue<Any>) : Runnable {
    
    
            override fun run() {
    
                try {
                    while (true) {
                        var any = queue.take()
                        System.out.println("消费者资源队列大小 ${queue.size}")
                        take(any)
                    }
                } catch (e: Exception) {
                    System.out.println("消费者中断")
                }
    
            }
    
    
            fun take(any: Any) {
                try {
                    Thread.sleep(1000)
                } catch (e: Exception) {
                    System.out.println("消费者使用中断")
                }
                System.out.println("消费对象 $any")
            }
        }
    }
    

    什么是Callable和Future?
    什么是FutureTask?
    什么是同步容器和并发容器的实现?

    什么是多线程?优缺点?

    • 多线程
      线程是存在于进程之中的它相当于一个任务,当个线程就是单个任务,多个线程就是多个任务,多线程可以提高程序的执行效率一般用于去处理那些比较耗时的操作,比如IO、网络、文件读写的操作。

    • 优缺点

    什么是多线程的上下文切换?

    ThreadLocal的设计理念与作用?

    • 设计理念
    1. 每一个线程都会持有一个ThreadLocalmap(静态内部类)
    2. ThreadLocalmap里有一个Entry数组,它是弱引用级别的一个子类。
    3. Entry数组会以当前ThreadLocal作为Key
    4. 所以每个线程持有不同的Entry数组,只有获取值得时候必须是和set方法调用线程,处于同一个线程。
    • 作用
      ThreadLocal用于在线程中存储数据,不想被其他线程访问,只能被调用set数据的线程所访问。

    ThreadPool(线程池)用法与优势?

    用法

    1. 通过ThreadPoolExecutor类来创建一个线程池主要参数有,线程次大小、线程池最大大小、线程活动保持时间、任务队列等。

    2. 通过Executors类工厂来创建

    • Executors.newSingleThreadExecutor();//单个后台线程

    • Executors.newFixedThreadPool(10);//固定大小线程池

    • Executors.newCachedThreadPool();//无界线程池,可以进行自动线程回收

    • Executors.newScheduledThreadPool(10);//定时线程池

    优势
    1.节省系统资源,线程池可以提高线程的复用效率,节省内存开销。

    1. 方便管理,可以对线程归纳到一起实行统一管理

    Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。

    synchronized和ReentrantLock的区别?
    Semaphore有什么作用?
    Java Concurrency API中的Lock接口(Lock interface)是什么?对比同步它有什么优势?
    Hashtable的size()方法中明明只有一条语句”return count”,为什么还要做同步?
    ConcurrentHashMap的并发度是什么?
    ReentrantReadWriteLock读写锁的使用?
    CyclicBarrier和CountDownLatch的用法及区别?
    LockSupport工具?
    Condition接口及其实现原理?
    Fork/Join框架的理解?

    wait()和sleep()的区别?

    • wait
      wait是Object方法它会让一个线程进入等待状态,通过需要nofity来唤醒

    • sleep
      sleep是Thread的方法,调用它会让一个线程进入等待超时状态,根据传入的时间会自己唤醒。

    线程的五个状态(五种状态,创建、就绪、运行、阻塞和死亡)?

    java线程在执行过程中,可能会处于以下图中的六种状态,在给定的一个时刻线程只能处于其中的一个状态。

    • NEW&初始状态
      创建一个线程但是没有调用.start方法
    new Thread();
    
    • RUNNABLE&运行状态
      调用start就会处于运行状态

    • BLOCKED&阻塞状态
      这个状态就是遇到了synchronized代码块或者方法,就会处于阻塞状态,如果获得了锁就会切换到运行状态

    • WAITING&等待状态
      表示线程进入等待状态,进入该状态需要其他线程做出一些特定的动作才能唤醒,wait()、join()、park()、方法都会导致线程进入等待状态,通过notify、notifyAll、unpark又会切回运行状态

    • TIME_WAITING&超时状态
      超时等待状态、不同于等待,这个状态如果没有被唤醒,达一定时间会自行返回。

    • TERMINATED*终止状态
      线程执行完毕的状态。

    image

    一张图看懂,每个状态进入的时间和切换的时机。


    image

    Thread源码中的State枚举类对状态的说明和定义

    public enum State {
            /**
             * Thread state for a thread which has not yet started.
             */
            NEW,
    
            /**
             * Thread state for a runnable thread.  A thread in the runnable
             * state is executing in the Java virtual machine but it may
             * be waiting for other resources from the operating system
             * such as processor.
             */
            RUNNABLE,
    
            /**
             * Thread state for a thread blocked waiting for a monitor lock.
             * A thread in the blocked state is waiting for a monitor lock
             * to enter a synchronized block/method or
             * reenter a synchronized block/method after calling
             * {@link Object#wait() Object.wait}.
             */
            BLOCKED,
    
            /**
             * Thread state for a waiting thread.
             * A thread is in the waiting state due to calling one of the
             * following methods:
             * <ul>
             *   <li>{@link Object#wait() Object.wait} with no timeout</li>
             *   <li>{@link #join() Thread.join} with no timeout</li>
             *   <li>{@link LockSupport#park() LockSupport.park}</li>
             * </ul>
             *
             * <p>A thread in the waiting state is waiting for another thread to
             * perform a particular action.
             *
             * For example, a thread that has called <tt>Object.wait()</tt>
             * on an object is waiting for another thread to call
             * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
             * that object. A thread that has called <tt>Thread.join()</tt>
             * is waiting for a specified thread to terminate.
             */
            WAITING,
    
            /**
             * Thread state for a waiting thread with a specified waiting time.
             * A thread is in the timed waiting state due to calling one of
             * the following methods with a specified positive waiting time:
             * <ul>
             *   <li>{@link #sleep Thread.sleep}</li>
             *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
             *   <li>{@link #join(long) Thread.join} with timeout</li>
             *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
             *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
             * </ul>
             */
            TIMED_WAITING,
    
            /**
             * Thread state for a terminated thread.
             * The thread has completed execution.
             */
            TERMINATED;
        }
    

    start()方法和run()方法的区别?

    • start
      start是Thrad的方法,它是用来真正的启动一个线程,调用完后线程状态就是新建的状态

    • run
      run是Runnable接口的方法,这个方法和普通方法没有区别,它一般作用于线程的执行体。

    Runnable接口和Callable接口的区别?

    volatile关键字的作用?

    让子线程每次读取值得时候都强制从主内存中读取

    在多线程情况下,每个线程都会有自己的一个本地变量栈。如果从主线程中读取一个变量,本地变量栈会从主内存中拷贝一个副本。以后每次子线程操作变量就是操作的副本,它的作用就是让线程每次都从主内存中读取。

    Java中如何获取到线程dump文件?
    线程和进程有什么区别?

    线程实现的方式有几种(四种)?

    1. 继承Thread类调用.start方法,重写run方法,这种方式不需要传入Runable对象。
     static class ThreadA extends Thread {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }
    
    1. 通过创建一个Thread类执行一个线程,传入Runable接口调用Thread的.start方法来开启一个线程
    1. Thread接收一个FutureTask来启动一个线程
     @Test
        fun testThread() {
            System.out.println(Thread.currentThread().id)
            var callable = ThreadA<String>()
            var oneTask = FutureTask<String>(callable)
            var t = Thread(oneTask)
            t.start()
        }
    
        class ThreadA<T> : Callable<T> {
            override fun call(): T? {
                System.out.println(Thread.currentThread().id)
                return null;
            }
    
        }
    
    1. ExecutorService来创建一个线程池启动

    高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?
    如果你提交任务时,线程池队列已满,这时会发生什么?
    锁的等级:方法锁、对象锁、类锁?
    如果同步块内的线程抛出异常会发生什么?
    并发编程(concurrency)并行编程(parallellism)有什么区别?
    如何保证多线程下 i++ 结果正确?
    一个线程如果出现了运行时异常会怎么样?

    如何在两个线程之间共享数据?

    如果执行代码是一样的话可以创建二个Thread线程,使用一个Runble变量传入,这样操作的就是同一个对象的变量了实现了共享。

    @Test
        fun testThread3() {
            var r = Runable1()
            var t1 = Thread(r)
            var t2 = Thread(r)
            t1.start()
            t2.start()
        }
    
    
        class Runable1 : Runnable {
    
            var count = 120
            override fun run() {
                synchronized(this) {
                    while (count > 0) {
                        count--
                        System.out.println("剩余票数$count 执行线程="+Thread.currentThread().name)
                    }
                }
    
            }
    
        }
    

    还有一种是代码不一样的情况,这样可以创建多个Runable对象,把要操作的数据封装到对象中,传入runable对象,加入同步关键字,这样虽然是不同的任务线程但是他们操作的同一个对象,也可以把要操作的数据设置成全局类型的,多个线程可以直接操作同一个变量。

    生产者消费者模型的作用是什么?

    怎么唤醒一个阻塞的线程?

    看什么情况下让线程进入了堵塞

    • Synchronize
      如果遇到同步关键字的话,未获取到锁会进入堵塞状态,等待获取锁后就会重新唤醒线程

    • notify notifyAll
      这种情况是通过对象的wait让线程进入了等待状态,通过这二个方法可以让等待的线程,重新唤醒进入运行状态。

    线程的Join是什么?

    join是Thread的一个方法,主要作用是在当前线程中调用另外一个线程的join方法,当前线程就会等待调用join方法的线程执行完毕后才继续往下执行。

    t.join完后,main线程必须会等待t1线程完成之后才继续执行。如果不加join有可能会出现t2线程先执行。

     @Test
        fun test() {
            var t1 = Thread(Runnable {
                Thread.sleep(1000)
                System.out.println(Thread.currentThread().name)
            })
    
            var t2 = Thread(Runnable {
                System.out.println(Thread.currentThread().name)
            })
    
            t1.start()
            t1.join()
            t2.start()
    
            Thread.sleep(1000)
    
        }
    

    Java中用到的线程调度算法是什么
    单例模式的线程安全性?
    线程类的构造方法、静态块是被哪个线程调用的?
    同步方法和同步块,哪个是更好的选择?

    如何检测死锁?怎么预防死锁?

    • 死锁代码
    public static void main(String[] args) {
    
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (A) {
                        try {
                            Thread.sleep(2000);
                            System.out.println("A");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        synchronized (B) {
                            System.out.println("1");
                        }
                    }
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (B) {
                        System.out.println("B");
                        synchronized (A) {
                            System.out.println("2");
                        }
                    }
                }
            });
    
            t1.start();
            t2.start();
    
        }
    
    • 检测死锁
      dump线程查看,死锁会导致系统永久无反应,业务逻辑是可以知道的。

    • 预防死锁

    1. 避免一个线程获取多个锁
    2. 一个线程不要过多占用资源
    3. 使用定时锁
    4. 对于数据库锁加锁解锁必须在一个数据库连接里,否则会出现解锁失败情况

    掘金

    相关文章

      网友评论

          本文标题:多线程TOP50

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