Java多线程面经题总结

基本概念
1、什么是进程?什么是线程?
进程就是在内存中执行的程序;线程是轻量级进程。

2、什么是并行?什么是并发?
并行:并行的关键是有同时处理多个任务的能力;
并发:有处理多个任务的能力,不一定要同时;

3、用户进程间通信机制?
共享内存:线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。
消息传递:线程之间没有公共的状态,线程之间必须通过发送消息进行显示通信

多线程的实现方法
1、创建多线程的方法
1、继承Thread类,重写run()方法;无返回值。
2、实现Runnable接口,重写run()方法。
创建Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
实现Runnable接口是一个task,需要分配一个线程。无返回值。
实现Callable接口。有返回值。
3、load锁

2、多线程的分类?
用户进程;
守护进程,最常见的守护线程:垃圾回收线程

3、常用方法
currentThread():返回对当前正在执行的线程对象的引用。
getId():返回此线程的标识符;
getName():返回此线程的名称;
getPriority():返回此线程的优先级;
isAlive():测试这个线程是否还处于活动状态;
sleep(long millis):使当前正在执行的线程以指定的毫秒数“休眠”(暂时停止执行);
interrupt():中断这个线程;
interrupted(): 测试当前线程是否已经是中断状态
setDaemon(boolean on):将此线程标记为 daemon线程或用户线程;
join():如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。join()方法是指等待调用join()方法的线程执行结束,程序才会继续执行下去。
yield():作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU时间。

4、wait/notify机制用于线程间的协同
等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()/notifyAll()方法,线程A收到通知后退出等待队列,进入可运行状态,进而执行后续操作。
上诉两个线程通过对象O来完成交互,而对象上的wait()方法和notify()/notifyAll()方法的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。
当方法wait()被执行后,锁自动被释放,但执行完notify()方法后,锁不会自动释放。必须执行完notify()方法所在的synchronized代码块后才释放。

5、wait()、sleep()和start()方法?
sleep():释放CPU的执行权,不释放锁;
wait():释放CPU的执行权,释放锁;
start():让线程跑起来;

6、公平锁与非公平锁.
Lock锁分为:公平锁 和 非公平锁。公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获取锁的,和公平锁不一样的就是先来的不一定先的到锁,这样可能造成某些线程一直拿不到锁,结果也就是不公平的了。
Service service = new Service(true);//true为公平锁,false为非公平锁

7、关键字volatile?
在当前的 Java 内存模型下,线程可以把变量保存高速缓存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。 要解决这个问题,就需要把变量声明为 volatile,这就指示 JVM,这个变量是不稳定的,每次使用它都到主存中进行读取和写入。在任何时刻,两个不同的线程总是看到某个成员变量的同一个值,这样也就保证了同步数据的可见性。volatile,这就指示 JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。
可见性:
volatile 修饰的成员变量在每次被线程访问时,都强迫从主存(共享内存)中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到主存(共享内存)。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值,这样也就保证了同步数据的可见性。

8、volatile和synchronized的比较?
1、volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。
2、多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞;
3、volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。
4、volatile关键字用于解决变量在多个线程之间的可见性,synchronized关键字解决的是多个线程之间访问资源的同步性。

9、什么是死锁?死锁的条件有哪些?
互斥条件:使用的资源是不能共享的。
请求与保持条件:线程持有一个资源并等待获取一个被其他线程持有的资源。
不可抢占条件:线程持有一个资源并等待获取一个被其他线程持有的资源。
循环等待条件:线程之间形成一种首尾相连的等待资源的关系。

线程同步
1、什么是线程安全?
当一个类,不断被多个线程调用,仍能表现出正确的行为时,那它就是线程安全的。多线程同时访问同一份资源,才有可能发生线程安全问题。
2、什么是线程同步?
多线程之间访问线程安全。线程同步是实现线程安全的一种手段。
3、什么是同步?什么是异步?
同步是指两个线程的运行是相关的,其中一个线程要阻塞等待另外一个线程的运行。异步的意思是两个线程毫无相关,自己运行自己的。

线程池
1、Executor 框架
Executor 框架结构主要由三大部分组成:
1、任务:执行任务需要实现的Runnable接口或Callable接口。
2、任务的执行:包括任务执行机制的核心接口Executor ,以及继承自Executor 接口的ExecutorService接口。ScheduledThreadPoolExecutor和ThreadPoolExecutor这两个关键类实现了ExecutorService接口。
3、异步计算的结果
2、各种线程池的适用场景介绍
FixedThreadPool: 适用于为了满足资源管理需求,而需要限制当前线程数量的应用场景。它适用于负载比较重的服务器;
SingleThreadExecutor: 适用于需要保证顺序地执行各个任务并且在任意时间点,不会有多个线程是活动的应用场景。
CachedThreadPool: 适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器;
ScheduledThreadPoolExecutor: 适用于需要多个后台执行周期任务,同时为了满足资源管理需求而需要限制后台线程的数量的应用场景;
SingleThreadScheduledExecutor: 适用于需要单个后台线程执行周期任务,同时保证顺序地执行各个任务的应用场景。
CAS算法????????????????????????????????????
CAS是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。实现非阻塞同步的方案称为“无锁编程算法”( Non-blocking algorithm)。
相对应的,独占锁是一种悲观锁,synchronized就是一种独占锁,它假设最坏的情况,并且只有在确保其它线程不会造成干扰的情况下执行,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。

各个方法区别
1、Java中wait、sleep、yield的区别?
1、sleep()和yield()方法是定义在Thread类中,而wait()方法是定义在Object类中的
2、wait()和sleep()的关键的区别在于,wait()是用于线程间通信的,而sleep()是用于短时间暂停当前线程。当一个线程调用wait()方法的时候,会释放它锁持有的对象的管程和锁,但是调用sleep()方法的时候,不会释放他所持有的管程。
3、yield()方法上来,与wait()和sleep()方法有一些区别,它仅仅释放线程所占有的CPU资源,从而让其他线程有机会运行,但是并不能保证某个特定的线程能够获得CPU资源。谁能获得CPU完全取决于调度器,在有些情况下调用yield方法的线程甚至会再次得到CPU资源。所以,依赖于yield方法是不可靠的,它只能尽力而为。
4、Java中的wait方法应在同步代码块中调用,但是sleep方法不需要。
5、使用sleep方法时,被暂停的线程在被唤醒之后会立即进入就绪态(Runnable state),但是使用wait方法的时候,被暂停的线程会首先获得锁,然后再进入就绪态。所以,根据你的需求,如果你需要暂定你的线程一段特定的时间就使用sleep()方法,如果你想要实现线程间通信就使用wait()方法。
2、wait和sleep区别?
1、wait只能在同步(synchronize)环境中被调用,而sleep不需要
2、进入wait状态的线程能够被notify和notifyAll线程唤醒,但是进入sleeping状态的线程不能被notify方法唤醒。
3、wait通常有条件地执行,线程会一直处于wait状态,直到某个条件变为真。但是sleep仅仅让你的线程进入睡眠状态。
4、wait方法在进入wait状态的时候会释放对象的锁,但是sleep方法不会。
5、wait方法是针对一个被同步代码块加锁的对象,而sleep是针对一个线程。
3、yield和sleep的区别
记住sleep和yield作用于当前线程。
yield方法会临时暂停当前正在执行的线程,来让有同样优先级的正在等待的线程有机会执行。如果没有正在等待的线程,或者所有正在等待的线程的优先级都比较低,那么该线程会继续运行。执行了yield方法的线程什么时候会继续运行由线程调度器来决定,不同的厂商可能有不同的行为。yield方法不保证当前的线程会暂停或者停止,但是可以保证当前线程在调用yield方法时会放弃CPU。
4、wait方法能不能被重写,wait能不能被中断?
wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写

猜你喜欢

转载自blog.csdn.net/wfh15140475085/article/details/88822507