多线程TOP50

2018-09-19  本文已影响9人  金馆长说

什么是线程?

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

特点

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

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

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

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

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

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?
什么是同步容器和并发容器的实现?

什么是多线程?优缺点?

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

ThreadLocal的设计理念与作用?

  1. 每一个线程都会持有一个ThreadLocalmap(静态内部类)
  2. ThreadLocalmap里有一个Entry数组,它是弱引用级别的一个子类。
  3. Entry数组会以当前ThreadLocal作为Key
  4. 所以每个线程持有不同的Entry数组,只有获取值得时候必须是和set方法调用线程,处于同一个线程。

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

用法

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

  2. 通过Executors类工厂来创建

优势
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()的区别?

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

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

new Thread();
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()方法的区别?

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对象,加入同步关键字,这样虽然是不同的任务线程但是他们操作的同一个对象,也可以把要操作的数据设置成全局类型的,多个线程可以直接操作同一个变量。

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

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

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

线程的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();

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

掘金

上一篇 下一篇

猜你喜欢

热点阅读