![](https://img-blog.csdnimg.cn/c9cbc21256cb4ce38723a9c11a0611c6.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
Java多线程面试题
Java多线程
复活的夜神月
这个作者很懒,什么都没留下…
展开
-
怎么防止死锁?
2. 使用tryLock()方法:可以使用ReentrantLock类的tryLock()方法,在获取锁时设置超时时间,避免一直等待而产生死锁。总之,在编写多线程应用程序时,要时刻关注并发安全问题,特别是死锁问题,尽量避免造成资源竞争和持有锁时间过长等问题,保证程序的高性能和稳定性。5. 尽量减少锁的持有时间:如果持有锁的时间过长,那么就会增加死锁的可能性,因此需要尽量减少锁的持有时间。4. 使用不同的锁:如果可以使用不同的锁来代替原有的锁,那么可以尝试使用不同的锁来避免死锁。原创 2023-06-06 14:57:24 · 3414 阅读 · 0 评论 -
ThreadLocal 是什么?有哪些使用场景?
ThreadLocal只是提供了隔离某个变量的机制,因而与多线程操作中的同步锁没有关联。为了保证ThreadLocal变量的正确性,ThreadLocal变量应该被声明为private static类型,这样可以保证它只被初始化一次,同时由于其是static类型,因此可以为某些需要使用ThreadLocal变量的地方提供全局的访问接口。ThreadLocal是Java中的一个线程相关类,它提供了一种变量在不同线程中的独立副本机制,每个线程能够获取到该变量的副本,而不会影响其他线程的副本数据。原创 2023-06-08 14:15:40 · 92 阅读 · 0 评论 -
synchronized 和 ReentrantLock 区别是什么?
4. 锁的可中断性:ReentrantLock支持锁的可中断性,也就是说,当一个线程在等待锁时,如果它调用lockInterruptibly()方法,那么当其它线程调用该线程的interrupt()方法中断它时,该线程能够中断等待状态,并抛出InterruptedException异常。2. 锁的可重入性:synchronized是可重入锁,也就是说,如果一个线程已经获得了锁,那么它可以重复地进入其它由该锁保护的synchronized代码块,而不必重新获得锁。原创 2023-06-09 11:08:42 · 314 阅读 · 0 评论 -
synchronized 和 Lock 有什么区别?
综上所述,synchronized 是 Java 内建的同步机制,使用简单方便,在并发度不高时性能表现更好,而 Lock 是 Java API 提供的线程同步机制,可以灵活定制锁的行为,但性能开销较大,适用于高并发的场景和对并发控制有更高要求的场景。1. 锁的获取方式:synchronized 机制是隐式获取锁,不需要用户手动获取和释放锁,当对象锁被释放时,其他线程可以再次获取这个锁;而 Lock 机制则需要手动获取/释放锁,即需要通过lock()方法获得锁,再通过unlock()方法释放锁。原创 2023-06-08 14:50:38 · 517 阅读 · 0 评论 -
synchronized 和 volatile 的区别是什么?
而 volatile 能够更加轻量级地实现变量的可见性,适用于只需要保证某个变量的可见性,而不需要同步控制的场景。2. 内存开销:synchronized 在使用时有一定的内存开销,需要进行锁的申请、释放、等待等操作,而 volatile 则没有锁的开销,通过 CPU 的缓存一致性实现了数据的可见性。4. 使用场景:synchronized 适用于需要在代码块或者方法上进行同步控制的场景,而 volatile 适用于只需要保证变量的可见性,而不需要保证多线程之间的原子性操作的场景。原创 2023-06-08 14:44:29 · 729 阅读 · 0 评论 -
说一下 synchronized 底层实现原理?
2. 轻量级锁:如果两个线程竞争同一把锁,那么会进入轻量级锁,尝试通过 CAS (Compare and Swap) 操作来获取锁,此时Mark Wold 会指向锁记录(Lock Record),锁记录中存储了指向锁的指针以及指向持有该锁的线程的指针,线程还是可以直接进入运行状态。3. 重量级锁:如果轻量级锁竞争失败,证明了锁资源存在争用,多个线程通过自旋锁来争取锁,但如果到达自旋的一定阈值仍然没有获取到锁,这时候就会升级为重量级锁,重量级锁,底层是通过操作系统底层的互斥量来实现线程阻塞和唤醒的。原创 2023-06-08 14:34:27 · 118 阅读 · 0 评论 -
创建线程池有哪几种方式?
3.使用Executors类:Java还提供了Executors类,该类提供了几个静态工厂方法,不同的方法可以根据具体需求来创建不同类型的线程池。例如,可以使用newFixedThreadPool方法来创建固定大小的线程池,或者使用newCachedThreadPool方法来创建一个没有大小限制的线程池。1.手动创建:手动编写代码来创建线程池,包括创建线程、管理线程的运行以及终止线程等操作。不同的应用场景需要不同的线程池,选择合适的方式可以提高程序的性能。原创 2023-06-06 14:23:53 · 1948 阅读 · 0 评论 -
多线程中 synchronized 锁升级的原理是什么?
1. 偏向锁:当没有线程访问一个对象的时候,这个对象的对象头中的Mark Word会被设置成偏向锁的状态。基于以上,所以锁升级的过程是从偏向锁开始,到轻量级锁和重量级锁的阶段。这样的转换也就是为了尽可能的减少不必要的锁竞争和CPU资源消耗,确保在多线程同步的问题中,锁的性能是越来越高的。锁升级的目的是提高代码的性能,减少锁等待的时间,增加并发处理能力。3. 重量级锁:如果CAS操作失败,虽然它会尝试自旋获取锁,但是锁对象则会撤销,升级到重量级锁。重量级锁使用操作系统提供的Mutex来实现线程同步操作。原创 2023-06-06 14:50:20 · 438 阅读 · 0 评论 -
线程的 run() 和 start() 有什么区别?
而当我们直接调用run()方法时,则会在当前线程中执行,不会产生新的线程。run()方法是Thread类中的一个普通方法,它是线程中实际运行的代码,线程的代码逻辑主要就是在run()方法中实现的。start()方法是Thread类中的一个启动方法,它会启动一个新的线程,并在新的线程中调用run()方法。直接调用run()方法,会像普通方法一样在当前线程中顺序执行run()方法的内容,这并不会启动一个新的线程。调用start()方法会创建一个新的线程,并在新的线程中并行执行run()方法的内容。原创 2023-06-05 14:39:07 · 3679 阅读 · 0 评论 -
线程池中 submit() 和 execute() 方法有什么区别?
submit()方法返回一个Future对象,可以使用这个对象的get()方法来获取任务执行的结果,或者使用get(timeout, unit)方法来获取任务执行结果,但是会有超时设置。submit()既可以提交Runnable任务,也可以提交Callable任务,会返回一个Future对象,可以用来获取任务执行结果。总之,使用execute()和submit()这两个方法都可以向线程池中提交任务,区别在于是否需要任务执行结果和是否能捕捉任务执行的异常。原创 2023-06-06 14:36:36 · 1203 阅读 · 1 评论 -
sleep() 和 wait() 有什么区别?
sleep()是Thread类中的静态方法,直接使用 Thread.sleep() 调用即可,而wait()则是Object类中的实例方法,必须通过监视器对象(即线程锁)调用,例如 synchronized(obj){ obj.wait();sleep()方法不会释放线程锁,即使当前线程持有某些运行时对象的锁,也不会在调用sleep()方法后释放锁。wait()方法则会释放线程锁,并在对象的等待集中等待,直到其他线程调用notify()或notifyAll()方法唤醒它,或者指定的等待时间到期。原创 2023-06-05 14:32:58 · 213 阅读 · 0 评论 -
线程池都有哪些状态?
5. Terminated(终止状态):当线程池处于Shutdown状态,并且等待队列中的任务全部执行完毕,或者在Stop状态下,线程池内部的所有线程都已经终止时,线程池进入Terminated状态。4. Tidying(整理状态):当线程池处于Shutdown或Stop状态时,如果等待队列中还有未执行的任务,则线程池将执行整理操作,将等待队列中的未执行任务移除,并保存到一个列表中。2. Shutdown(关闭状态):线程池调用shutdown()方法后,线程池的状态会变为Shutdown。原创 2023-06-06 14:28:51 · 2429 阅读 · 0 评论 -
线程有哪些状态?
需要注意的是,不同的线程状态可以通过Thread类中的getState()方法来获取,也可以通过查看JVM的线程状态报告来得知。其中,NEW和TERMINATED状态比较容易理解,而RUNNABLE、BLOCKED、WAITING和TIMED_WAITING则是线程状态中最常见的一些状态。5. TIMED_WAITING:超时等待状态,即线程等待某个对象一段时间后自动唤醒。4. WAITING:等待状态,即线程在某个对象上等待,直到其他线程唤醒它。原创 2023-06-05 14:26:09 · 53 阅读 · 0 评论 -
什么是死锁?
一个产生死锁的简单例子是:假设有两个线程A和B,它们都需要获取一个资源S,它们先后获取了自己需要的资源,但由于某些原因,它们都无法继续执行,因为它们都在等待对方释放自己需要的资源。这种情况下,A等待B释放S资源,B等待A释放S资源,它们无法继续执行,形成了死锁。死锁是指两个或多个线程互相持有对方所需要的资源,然后因互相等待而阻塞的现象。死锁是多线程编程中比较常见的问题,常见原因包括错误的锁顺序、竞争过度的资源以及不合理的等待时间等等。原创 2023-06-06 14:52:15 · 73 阅读 · 0 评论 -
在 Java 程序中怎么保证多线程的运行安全?
这种方式需要注意锁的粒度,使得锁住的代码块尽可能的短,以避免影响程序性能。3. 使用Lock对象:Lock是JDK提供的同步机制,Lock提供的Lock()和Unlock()方法可以在同一个时刻,只允许一个线程进入执行Lock()和Unlock()方法之间的代码块,其他线程必须等待。在多线程的编程中,要注重多线程的协作,避免死锁和饥饿等问题的出现,同时在程序设计中尽量减少共享资源的数量,以减少多线程运行时的竞争情况,从而提高程序性能。原创 2023-06-06 14:43:27 · 1954 阅读 · 0 评论 -
notify()和 notifyAll()有什么区别?
因此,在多线程编程中,如果需要唤醒所有等待该对象的线程,则可以使用notifyAll()方法;notifyAll()方法则会唤醒等待队列中的所有线程,并使它们竞争获取锁,这样可以使所有线程都有机会获取锁并进入运行状态,从而避免了一些线程一直处于等待状态。notify()方法只会唤醒等待队列中的一个线程,并使其与其他线程竞争获取锁,这可能会导致某些线程无法被唤醒或者一直处于等待状态。notify()方法只会随机唤醒等待队列中的一个线程,而notifyAll()方法则会唤醒等待队列中的所有线程。原创 2023-06-05 14:37:04 · 3117 阅读 · 1 评论