2023

您所在的位置:网站首页 多线程高级面试题 2023

2023

2023-05-19 00:59| 来源: 网络整理| 查看: 265

什么是线程死锁

线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。

产生死锁的必要条件

互斥条件:该资源任意一个时刻只由一个线程占用。

请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

如何避免线程死锁?

破坏互斥条件 :这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。

破坏请求与保持条件 :一次性申请所有的资源。

破坏不剥夺条件 :占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。

破坏循环等待条件 :靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。

线程的run()和start()有什么区别?

start() 方法用于启动线程,run() 方法用于执行线程的运行时代码。调用start()方法使线程处于就绪状态,当cpu分配到时间片后自动执行run() 中的代码, run()方法运行结束, 此线程终止。然后CPU再调度其它线程。

Synchronized 用过吗,其原理是什么?

synchronized的锁对象中有一个计数器(recursions变量)会记录线程获得几次锁;

可重入的好处:可以避免死锁;

不可中断性:一个线程获得锁后,另一个线程想要获得锁,必须处于阻塞或等待状态,如果第一个线程不释放锁,第二个线程会一直阻塞或等待,不可被中断。

synchronized 属于不可被中断;

Lock lock方法是不可中断的;

Lock tryLock方法是可中断的;

wait(), notify()和 notifyAll()

wait() 线程等待,notify() 唤醒(单个线程)wait() ,nottfyAll() 唤醒全部线程 

ThreadLocal和Synchronized区别

synchronized主要解决多线程共享数据同步问题。

ThreadLocal主要解决多线程中数据因并发产生不一致问题。

Thread 类中的 yield 方法有什么作用?

使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

sleep() 和yield() 有什么区别?

sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态 sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常

yield方法和wait方法

yield()方法属于高风亮节方法,可以调用跟自己同级的线程 也不会释放锁

wait()方法是Object对象的方法,使用时候调用对象的wait方法导致当前对象放弃对象的锁,只有调用notify方法或者notifyAll方法才会唤醒 。会释放锁 join对象也可以

sleep()方法是休眠方法,是Thread类的静态方法,调用时不会释放锁。

堆区:只存放类对象,线程共享

方法区:又叫静态存储区,存放class文件和静态数据,线程共享

栈区:存放方法局部变量,基本类型变量区,执行环境上下文、操作指令区,线程不共享。

为什么说 Synchronized 是非公平锁?

当锁被释放后,任何一个线程都有机会竞争得到锁,这样做的目的是提高效率,但缺点是可能产生线程饥饿现象。

为什么说 Synchronized 是一个悲观锁?乐观锁的实现原理又是什么?什么是 CAS,它有什么特性? Synchronized的并发策略是悲观的,不管是否产生竞争,任何数据的操作都必须加锁。

乐观锁的核心是CAS,CAS包括内存值、预期值、新值,只有当内存值等于预期值时,才会将内存值修改为新值。

乐观锁一定就是好的吗?

乐观锁认为对一个对象的操作不会引发冲突,所以每次操作都不进行加锁,只是在最后提交更改时验证是否发生冲突,如果冲突则再试一遍,直至成功为止,这个尝试的过程称为自旋。

乐观锁没有加锁,但乐观锁引入了ABA问题,此时一般采用版本号进行控制; 也可能产生自旋次数过多问题,此时并不能提高效率,反而不如直接加锁的效率高; 只能保证一个对象的原子性,可以封装成对象,再进行CAS操作;

请尽可能详尽地对比下 Synchronized 和 ReentrantLock 的异同。

1、相似点

它们都是阻塞式的同步,也就是说一个线程获得了对象锁,进入代码块,其它访问该同步块的线程都必须阻塞在同步代码块外面等待,而进行线程阻塞和唤醒的代码是比较高的。

2、功能区别

Synchronized是java语言的关键字,是原生语法层面的互斥,需要JVM实现;ReentrantLock 是JDK1.5之后提供的API层面的互斥锁,需要lock和unlock()方法配合try/finally代码块来完成。 Synchronized使用较ReentrantLock 便利一些; 锁的细粒度和灵活性:ReentrantLock强于Synchronized;

3、性能区别

Synchronized引入偏向锁,自旋锁之后,两者的性能差不多,在这种情况下,官方建议使用Synchronized。

创建线程池的几个核心构造参数 // Java线程池的完整构造函数 public ThreadPoolExecutor( int corePoolSize, // 线程池长期维持的最小线程数,即使线程处于Idle状态,也不会回收。 int maximumPoolSize, // 线程数的上限 long keepAliveTime, // 线程最大生命周期。 TimeUnit unit, //时间单位 BlockingQueue workQueue, //任务队列。当线程池中的线程都处于运行状态,而此时任务数量继续增加,则需要一个容器来容纳这些任务,这就是任务队列。 ThreadFactory threadFactory, // 线程工厂。定义如何启动一个线程,可以设置线程名称,并且可以确认是否是后台线程等。 RejectedExecutionHandler handler // 拒绝任务处理器。由于超出线程数量和队列容量而对继续增加的任务进行处理的程序。 ) ThreadLocal 是什么?有哪些使用场景?

ThreadLocal 是一个本地线程副本变量工具类,在每个线程中都创建了一个 ThreadLocalMap 对象,简单说 ThreadLocal 就是一种以空间换时间的做法,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。通过这种方式,避免资源在多线程间共享。

经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题。

请谈谈 ThreadLocal 是怎么解决并发安全的?

在java程序中,常用的有两种机制来解决多线程并发问题,一种是sychronized方式,通过锁机制,一个线程执行时,让另一个线程等待,是以时间换空间的方式来让多线程串行执行。而另外一种方式就是ThreadLocal方式,通过创建线程局部变量,以空间换时间的方式来让多线程并行执行。两种方式各有优劣,适用于不同的场景,要根据不同的业务场景来进行选择。

Java 中的线程池是如何实现的

创建一个阻塞队列来容纳任务,在第一次执行任务时创建足够多的线程,并处理任务,之后每个工作线程自动从任务队列中获取线程,直到任务队列中任务为0为止,此时线程处于等待状态,一旦有工作任务加入任务队列中,即刻唤醒工作线程进行处理,实现线程的可复用性。

线程池一般包括四个基本组成部分:

1、线程池管理器

用于创建线程池,销毁线程池,添加新任务。

2、工作线程

线程池中线程,可循环执行任务,在没有任务时处于等待状态。

3、任务队列

用于存放没有处理的任务,一种缓存机制。

4、任务接口

每个任务必须实现的接口,供工作线程调度任务的执行,主要规定了任务的开始和收尾工作,和任务的状态。

volatile 关键字的作用

对于可见性,Java 提供了 volatile 关键字来保证可见性和禁止指令重排。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

从实践角度而言,volatile 的一个重要作用就是和 CAS 结合,保证了原子性,详细的可以参见 java.util.concurrent.atomic 包下的类,比如 AtomicInteger。

volatile 常用于多线程环境下的单次操作(单次读或者单次写)。  

很多人都说要慎用 ThreadLocal,谈谈你的理解,使用 ThreadLocal 需要注意些什么?

线程之间的threadLocal变量是互不影响的,

使用private final static进行修饰,防止多实例时内存的泄露问题

线程池环境下使用后将threadLocal变量remove掉或设置成一个初始值



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3