面试-线程

一、如何保证线程安全?

答:通过合理的时间调度,避开贡献资源的存取冲突。另外,在并行任务设计上可以通过适当的策略,保证任务与任务之间不存在共享资源,设计一个规则来保证一个客户的计算工作和数据访问只会被一个线程或一台工作机完成,而不是把一个客户的计算工作分配给多个线程去完成。

二、请你简要说明一下线程的基本状态以及状态之间的关系?

答:其中Running表示运行状态,Runnable表示就绪状态,Blocked表示阻塞状态,阻塞状态又有多种情况,可能是因为调用wait()方法进入等待池,也可能是执行同步方法或同步代码块进入等锁池,或者是调用了sleep()方法或join()方法等待休眠或其他线程结束,或者是因为发生了I/O中断。

三、请你解释一下什么是线程池?

答:在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其他更多资源。在java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。这就是“池化资源”技术产生的原因。

线程池顾名思义就是事先创建若干个可执行的线程放入一个池中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。

Java + 中的Executor接口定义一个执行线程的工具。它的子类型即线程池接口是ExecutorService。要配置一个线程池是比较复杂的,尤其是对于线程池的原因不是很清楚的情况下,因此在工具类Executors面提供了一些静态工厂方法,生成一些常用的线程池。如下所示:

①newSingleThreadExecutor:创建一个单线程的线程池。

②newFixedThreadPool:创建固定大小的线程池。

③newCachedThreadPool:创建一个可缓存的线程池。

④newScheduledThreadPool:创建一个大小无限的线程池。

⑤newSingleThreadExecutor:创建一个单线程的线程池。

四、举例说明同步和异步?

答:如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就必须进行同步存取。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。事实上,所谓的同步就是指阻塞式操作,而异步就是非阻塞式操作。

五、请介绍一下线程同步和线程调度的相关方法。

答:wait():使一个线程处于等待状态,并且释放所持有的对象的锁。

sleep():使一个正在运行的线程处于睡眠的状态,是一个静态方法。

notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而不是由JVM确定唤醒哪个线程,而且与优先级无关。

notify():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态。

六、请问当一个线程进入一个对象的synchronized方法A之后,其他线程是否可以进入此对象的synchronized方法B?

答:不能,其他线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等待锁池中等待对象的锁。

七、请简述一下线程的sleep()方法和yield()方法有什么区别?

答:①sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会。

②线程执行sleep()方法后转入阻塞状态,而执行yield()方法后转入就绪状态。

③sleep()方法比yield()方法具有更好的可移植性。

八、请分别说明一下多线程和同步有几种实现方法,并且这些实现方法具体内容都是什么?

答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口同步的实现方面有两种,分别是synchronized,wait与notify。

九、请你说出你所知道的线程同步的方法。

答:wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

notifyAll():唤醒所有处于等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

十、启动一个线程是用run()还是start()?

答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行,这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。

十一、请说明一下sleep()和wait()有什么区别?

答:sleep是线程类的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时会自动恢复。调用sleep不会释放对象锁。

wait是object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法后本线程才进入对象锁定池准备获得对象池进入运行状态。

十二、请你分析一下同步方法和同步代码块的区别是什么?

答:同步方法默认用this或者当前类class对象作为锁;

同步代码块可以选择以什么来加锁,比同步方法要更细颗粒度,我们可以选择只同步会发生同步问题的部分代码而不是整个方法。

十三、请你解释一下Java多线程回调是什么意思?

答:所谓回调,就是客户程序C调用服务程序S中的某个方法A,然后S又在某个时候反过来调用C中的某个方法B,对于C来说,这个B便叫做回调方法。

十四、请说明一下线程池有什么优势?

答:①降低资源能耗;②提高响应速度;③提高线程的可管理性。

十五、请说明一下Java中都有哪些方式可以启动一个线程?

答:①继承自Thread类。②实现Runable接口。③即实现Runnable接口,也继承Thread类,并重写run方法。

十六、请列举一个创建线程的方法,并简要说明一下在这些方法中哪个方法更好,原因是什么?

答:需要从java.lang.Thread类派生一个新的线程类,重载它的run()方法;

实现Runable接口,重载Runable接口中的run()方法。

实现Runnable接口更好,可以处理同一资源,从而实现资源的共享。

十七、请介绍一下什么是生产者消费者模式?

答:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。

十八、多线程中的i++线程安全吗?请简述一下原因?

答:不安全。i++不是原子性操作。i++分为读取i,对i值加一,再赋值给i++,执行期中任何一步都是有可能被其他线程抢占的。

十九、如何在线程安全的情况下实现一个计数器?

答:可以使用加锁,比如synchronized或者lock,也可以使用Concurrent包下的原子类。

二十、线程、进程,然后线程创建有很大开销,怎么优化?

答:可以使用线程池。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值