Java面试题——多线程问题及答案

文章目录

        • 创建子线程时,子线程是得不到父线程的 ThreadLocal,有什么办法可以解决这个问题?
        • 多线程的几种实现方式,什么是线程安全。
        • 实现Runnable接口和继承Thread类哪个更好?
        • volatile的原理,作用,能代替锁么。
        • 画一个线程的生命周期状态图。
        • 什么是线程?它与进程有什么区别?为什么要使用多线程
        • 同步和异步有什么区别
        • run()方法和start()方法有什么区别
        • 一个线程两次调用start()方法会出现什么情况?为什么?
        • 多线程同步的实现方法有哪些
        • sleep和wait的区别。
            • sleep和sleep(0)的区别。
            • sleep和yield方法的区别
        • 终止线程的方法有哪些
        • Lock与Synchronized的区别 。
        • join()方法的作用是什么
        • synchronized的原理是什么,一般用在什么地方(比如加在静态方法和非静态方法的区别,静态方法和非静态方法同时执行的时候会有影响吗)
        • 解释以下名词:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。
        • 用过哪些原子类,他们的原理是什么。
        • JUC下研究过哪些并发工具,讲讲原理。
        • 用过线程池吗,如果用过,请说明原理,并说说newCache和newFixed有什么区别,构造函数的各个参数的含义是什么,比如coreSize,maxsize等。
        • 线程池的关闭方式有几种,各自的区别是什么。
        • 假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多有10个线程同时调用它,如何做到。
        • spring的controller是单例还是多例,怎么保证并发的安全。
        • 用三个线程按顺序循环打印abc三个字母,比如abcabcabc。
        • ThreadLocal用过么,用途是什么,原理是什么,用的时候要注意什么。
        • 如果让你实现一个并发安全的链表,你会怎么做。
        • 有哪些无锁数据结构,他们实现的原理是什么。
        • 讲讲java同步机制的wait和notify。
        • CAS机制是什么,如何解决ABA问题。
        • 多线程如果线程挂住了怎么办。
        • countdowlatch和cyclicbarrier的内部原理和用法,以及相互之间的差别(比如countdownlatch的await方法和是怎么实现的)。
        • 对AbstractQueuedSynchronizer了解多少,讲讲加锁和解锁的流程,独占锁和公平锁
        • 简述ConcurrentLinkedQueue和LinkedBlockingQueue的用处和不同之处。
        • 导致线程死锁的原因?怎么解除线程死锁。
        • 非常多个线程(可能是不同机器),相互之间需要等待协调,才能完成某种工作,问怎么设计这种协调方案。
        • 用过读写锁吗,原理是什么,一般在什么场景下用。
        • 开启多个线程,如果保证顺序执行,有哪几种实现方式,或者如何保证多个线程都执行完再拿到结果。
        • 延迟队列的实现方式,delayQueue和时间轮算法的异同。

创建子线程时,子线程是得不到父线程的 ThreadLocal,有什么办法可以解决这个问题?

答:这道题主要考察线程的属性和创建过程,可以这么回答。

可以使用 InheritableThreadLocal 来代替 ThreadLocal,ThreadLocal 和 InheritableThreadLocal 都是线程的属性,所以可以做到线程之间的数据隔离,在多线程环境下我们经常使用,但在有子线程被创建的情况下,父线程 ThreadLocal 是无法传递给子线程的,但 InheritableThreadLocal 可以,主要是因为在线程创建的过程中,会把

InheritableThreadLocal 里面的所有值传递给子线程,具体代码如下:

// 当父线程的 inheritableThreadLocals 的值不为空时
// 会把 inheritableThreadLocals 里面的值全部传递给子线程
if (parent.inheritableThreadLocals != null)
    this.inheritableThreadLocals =
        ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

多线程的几种实现方式,什么是线程安全。

四种:
1、继承Thread类,重写run()方法,
2、实现Runnable接口,实现run()方法
3、实现Callable接口,重写call()方法
与Runnable接口相比,可以实现的功能:提供返回值,抛出异常,拿到Future对象,获取异步的结果。
4、使用线程池。

Java面试题——多线程问题及答案_第1张图片

实现Runnable接口和继承Thread类哪个更好?

Runnable接口更好
1、代码架构角度
具体的任务,run方法里面的任务,创建线程。从生命周期的角度看,实现Runnable接口可以实现解耦。
2、新建线程的损耗
Thread需要new,还要销毁;Runnable可以反复利用一个线程
3、Java不支持多继承

volatile的原理,作用,能代替锁么。

volatile的理解

画一个线程的生命周期状态图。

Java面试题——多线程问题及答案_第2张图片
1、新建状态(New)

用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable)。

注意:不能对已经启动的线程再次调用start()方法,否则会出现java.lang.IllegalThreadStateException异常。

2、就绪状态(Runnable)

处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线 程就绪队列(尽管是采用队列形式,事实上,把它称为可运行池而不是可运行队列。因为cpu的调度不一定是按照先进先出的顺序来调度的),等待系统为其分配 CPU。等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“cpu调 度”。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。

提示:如果希望子线程调用start()方法后立即执行,可以使用Thread.sleep()方式使主线程睡眠一伙儿,转去执行子线程。

3、运行状态(Running)

处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

处于就绪状态的线程,如果获得了cpu的调度,就会从就绪状态变为运行状态,执行run()方法中的任务。如果该线程失去了cpu资源,就会又从运 行状态变为就绪状态。重新等待系统分配资源。也可以对在运行状态的线程调用yield()方法,它就会让出cpu资源,再次变为就绪状态。

当发生如下情况是,线程会从运行状态变为阻塞状态:

①、线程调用sleep方法主动放弃所占用的系统资源

②、线程调用一个阻塞式IO方法,在该方法返回之前,该线程被阻塞

③、线程试图获得一个同步监视器,但更改同步监视器正被其他线程所持有

④、线程在等待某个通知(notify)

⑤、程序调用了线程的suspend方法将线程挂起。不过该方法容易导致死锁,所以程序应该尽量避免使用该方法。

当线程的run()方法执行完,或者被强制性地终止,例如出现异常,或者调用了stop()、desyory()方法等等,就会从运行状态转变为死亡状态。

4、阻塞状态(Blocked)

处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。阻塞的情况分三种:

(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁(synchronized)被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行。有三种方法可以暂停Threads执行。

5、死亡状态(Dead)

需要说明的是,synchronized锁和调用wait()的对象应为同一对象!否则会报java.lang.IllegalMonitorStateException错误。
详细说明

什么是线程?它与进程有什么区别?为什么要使用多线程

线程是指程序在执行过程中,能够执行程序代码的一个执行单元。Java语言中,线程有4中状态:运行、就绪、挂起和结束。
进程是指一段正在执行的程序。
线程也被称为轻量级进程,是程序执行的最小单元,一个进程可以有多个线程,各个线程之间共享程序的内存单元和进程级资源,但是各个线程都有自己的栈空间。
为什么使用多线程?原因:
1、可以减少程序的响应时间。单线程情况下,某个操作很耗时,就会。。
2、线程的创建和切换开销更小。
3、多CPU或多核计算机本身就有执行多线程的能力。
4、简化程序结构,便于理解和维护。

同步和异步有什么区别

同步:数据共享问题,当多个线程需要访问同一个资源时,需要确保某一时刻只能被一个线程使用,能够保证资源的安全。
异步:每个线程都包含了运行时自己所需要的数据或方法。在进程输入输出的时候,不必关心其他线程的状态或行为。

run()方法和start()方法有什么区别

start()方法来启动一个线程,该线程处于就绪状态,可以被JVM来调度。JVM通过调用run()方法来完成实际的操作。(异步)
如果直接调用run()方法,则是普通的函数调用。(同步)

一个线程两次调用start()方法会出现什么情况?为什么?

会出现IllegalThreadStateException异常;start()方法调用时候会先检查状态,不符合所以会抛出异常

多线程同步的实现方法有哪些

(1)synchronized关键字
~~synchronized方法
~~synchronized块
(2)wait()方法与notify()方法
(3)Lock
~~lock()不会抛出异常
~~tryLock()
~~tryLock(long timeout,TimeUnit unit)
~~lockInterruptibly()

sleep和wait的区别。

sleep()和wait()都是使线程暂停执行一段时间的方法。区别如下:
(1)原理
sleep()是Thread类的静态方法,是线程控制自身流程的
wait()方法是Object类的方法,用于线程间通信,其他线程调用notify()方法才“醒”来,也可以设定一个时间。
(2)锁的处理机制不同
sleep()不会释放锁,wait()会。
(3)使用区域不同
wait()只能在同步方法或块,sleep()在任何地方。

sleep和sleep(0)的区别。

Sleep(0),如果线程调度器的可运行队列中有大于或等于当前线程优先级的就绪线程存在,操作系统会将当前线程从处理器上移除,调度其他优先级高的就绪线程运行;如果可运行队列中的没有就绪线程或所有就绪线程的优先级均低于当前线程优先级,那么当前线程会继续执行,就像没有调用 Sleep(0)一样。

sleep和yield方法的区别

1、sleep方法给其他线程运行机会时不考虑线程的优先级,因此会给低线程优先级运行的机会,而yield方法只会给相同优先级或者更高优先级线程运行的机会

2、线程执行sleep()方法后转入阻塞状态,所以,执行sleep()方法的线程在指定的时间内不会被执行,而yield()方法只是使当前线程重新回到可执行状态,所以执行yield()方法的线程可能在进入可执行状态后马上又被执行

3、sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常

4、sleep()方法比yield()方法(跟操作系统相关)有更好的可移植性

终止线程的方法有哪些

stop()和suspend()方法

Lock与Synchronized的区别 。

(1)用法
(2)性能
(3)锁机制

join()方法的作用是什么

让调用该方法的线程在执行完run()后,再执行join方法后面的代码。

synchronized的原理是什么,一般用在什么地方(比如加在静态方法和非静态方法的区别,静态方法和非静态方法同时执行的时候会有影响吗)

原理
static的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对象),那么static获取到的锁,是属于类的锁。而非static方法获取到的锁,是属于当前对象的锁。所以,他们之间不会产生互斥。

解释以下名词:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。

https://blog.csdn.net/qq_33805483/article/details/104099367

用过哪些原子类,他们的原理是什么。

AtomicInteger,原理CAS,unSafe类。

JUC下研究过哪些并发工具,讲讲原理。

提供了线程池的创建类 ThreadPoolExecutor、Executors 等;
提供了各种锁,如 Lock、ReentrantLock 等;
提供了各种线程安全的数据结构,如 ConcurrentHashMap、LinkedBlockingQueue、DelayQueue 等;
提供了更加高级的线程同步结构,如 CountDownLatch、CyclicBarrier、Semaphore 等。

用过线程池吗,如果用过,请说明原理,并说说newCache和newFixed有什么区别,构造函数的各个参数的含义是什么,比如coreSize,maxsize等。

线程池
newCache是创建可扩容的带有缓存的一池多线程
newFixed是创建固定个数的线程池

线程池的关闭方式有几种,各自的区别是什么。

shutdown:
1、调用之后不允许继续往线程池内继续添加线程;
2、线程池的状态变为SHUTDOWN状态;
3、所有在调用shutdown()方法之前提交到ExecutorSrvice的任务都会执行;
4、一旦所有线程结束执行当前任务,ExecutorService才会真正关闭。

shutdownNow():
1、该方法返回尚未执行的 task 的 List;
2、线程池的状态变为STOP状态;
3、阻止所有正在等待启动的任务, 并且停止当前正在执行的任务。

假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多有10个线程同时调用它,如何做到。

ScheduledThreadPoolExecutor 设置定时,进行调度,可以用来在给定延时后执行异步任务或者周期性执行任务。

 public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { 	  
      super(corePoolSize, Integer.MAX_VALUE, 0,TimeUnit.NANOSECONDS, new DelayedWorkQueue(),threadFactory);
 }

spring的controller是单例还是多例,怎么保证并发的安全。

单例,通过单例工厂 DefaultSingletonBeanRegistry实现单例;
AsyncTaskExecutor保证并发的安全。

用三个线程按顺序循环打印abc三个字母,比如abcabcabc。

public static void main(String[] args) {
	final String str=”abc”;
	ExecutorService executorService= Executors.newFixedThreadPool(3);
	executorService.execute(new Runnable() {
	@Override
	public void run() {
	System.out.println(1+str);
	}
	});executorService.execute(new Runnable() {
	@Override
	public void run() {
	System.out.println(2+str);
	}
	});executorService.execute(new Runnable() {
	@Override
	public void run() {
	System.out.println(2+str);
	}
	});
}

ThreadLocal用过么,用途是什么,原理是什么,用的时候要注意什么。

ThreadLocal有什么用

如果让你实现一个并发安全的链表,你会怎么做。

Collections.synchronizedList() ConcurrentLinkedQueue

有哪些无锁数据结构,他们实现的原理是什么。

CAS基于jdk提供的原子类原语实现,例如AtomicReference

讲讲java同步机制的wait和notify。

CAS机制是什么,如何解决ABA问题。

CAS

多线程如果线程挂住了怎么办。

根据具体情况(sleep,wait,join等),酌情选择notifyAll,notify进行线程唤醒。

countdowlatch和cyclicbarrier的内部原理和用法,以及相互之间的差别(比如countdownlatch的await方法和是怎么实现的)。

1
2

对AbstractQueuedSynchronizer了解多少,讲讲加锁和解锁的流程,独占锁和公平锁

简述ConcurrentLinkedQueue和LinkedBlockingQueue的用处和不同之处。

导致线程死锁的原因?怎么解除线程死锁。

非常多个线程(可能是不同机器),相互之间需要等待协调,才能完成某种工作,问怎么设计这种协调方案。

用过读写锁吗,原理是什么,一般在什么场景下用。

开启多个线程,如果保证顺序执行,有哪几种实现方式,或者如何保证多个线程都执行完再拿到结果。

延迟队列的实现方式,delayQueue和时间轮算法的异同。

你可能感兴趣的:(面试-并发)