志在指尖
用双手敲打未来

java多线程(面试题及答案)

java多线程

线程是程序的基本执行单元。当操作系统(不包括单线程操作系统,例如Microsoft的早期DOS)正在执行程序时,将在系统中创建一个进程,并且在此进程中,必须至少创建一个线程(该线程称为主线程)作为该程序运行的入口点。因此,在操作系统中运行的任何程序都至少具有一个主线程。
线程不仅可以共享进程的内存,还可以拥有自己的内存空间。该线程不仅可以共享进程的内存,还可以拥有自己的内存空间。本节使用的数据,例如线程执行函数中定义的变量。
线:java
1.线程是轻量级进程
2.线程没有独立的地址空间(内存空间)
3.线程是由进程创建的(进程中寄生的)
4.一个进程可以有多个线程->这就是我们通常所说的多线程编程
5.线程具有几种状态:
a。新状态(新)
b。就绪状态(可运行)
C。运行状态(Running)
d,阻塞状态(Blocked)
e,死亡状态(死者)

java多线程面试题及答案

1、多线程有什么用?
一个或许在许多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡。所谓”知其然知其所以然”,”会用”仅仅”知其然”,”为什么用”才是”知其所以然”,只需抵达”知其然知其所以然”的程度才能够说是把一个常识点游刃有余。OK,下面说说我对这个问题的观点:
1)发挥多核CPU的优势
跟着工业的进步,现在的笔记本、台式机乃至商用的应用服务器至少也都是双核的,4核、8核乃至16核的也都不罕见,假如是单线程的程序,那么在双核CPU上就浪费了50%,在4核CPU上就浪费了75%。单核CPU上所谓的”多线程”那是假的多线程,同一时刻处理器只会处理一段逻辑,只不过线程之间切换得比较快,看着像多个线程”一起”运转算了。多核CPU上的多线程才是真实的多线程,它能让你的多段逻辑一起作业,多线程,能够真实发挥出多核CPU的优势来,抵达充分利用CPU的目的。
2)避免堵塞
从程序运转功率的视点来看,单核CPU不但不会发挥出多线程的优势,反而会由于在单核CPU上运转多线程导致线程上下文的切换,而降低程序全体的功率。可是单核CPU咱们仍是要应用多线程,便是为了避免堵塞。试想,假如单核CPU运用单线程,那么只需这个线程堵塞了,比方说远程读取某个数据吧,对端迟迟未回来又没有设置超时时刻,那么你的整个程序在数据回来回来之前就中止运转了。多线程能够避免这个问题,多条线程一起运转,哪怕一条线程的代码履行读取数据堵塞,也不会影响其它使命的履行。
3)便于建模
这是别的一个没有这么明显的优点了。假定有一个大的使命A,单线程编程,那么就要考虑许多,树立整个程序模型比较麻烦。可是假如把这个大的使命A分解成几个小使命,使命B、使命C、使命D,别离树立程序模型,并经过多线程别离运转这几个使命,那就简略许多了。
2、创立线程的办法
比较常见的一个问题了,一般便是两种:
1)承继Thread类
2)完结Runnable接口
至于哪个好,不用说肯定是后者好,由于完结接口的办法比承继类的办法更灵敏,也能削减程序之间的耦合度,面向接口编程也是设计形式6大原则的中心。
其实还有第3种,点击这儿了解更多。
3、start()办法和run()办法的差异
只需调用了start()办法,才会表现出多线程的特性,不同线程的run()办法里边的代码交替履行。假如仅仅调用run()办法,那么代码仍是同步履行的,必须等候一个线程的run()办法里边的代码全部履行结束之后,别的一个线程才能够履行其run()办法里边的代码。
4、Runnable接口和Callable接口的差异
有点深的问题了,也看出一个Java程序员学习常识的广度。
Runnable接口中的run()办法的回来值是void,它做的事情仅仅纯粹地去履行run()办法中的代码罢了;Callable接口中的call()办法是有回来值的,是一个泛型,和Future、FutureTask合作能够用来获取异步履行的成果。
这其实是很有用的一个特性,由于多线程相比单线程更难、更复杂的一个重要原因便是由于多线程充满着未知性,某条线程是否履行了?某条线程履行了多久?某条线程履行的时分咱们期望的数据是否现已赋值结束?无法得知,咱们能做的仅仅等候这条多线程的使命履行结束罢了。而Callable+Future/FutureTask却能够获取多线程运转的成果,能够在等候时刻太长没获取到需求的数据的状况下撤销该线程的使命,真的是十分有用。
5、CyclicBarrier和CountDownLatch的差异
两个看上去有点像的类,都在java.util.concurrent下,都能够用来表明代码运转到某个点上,二者的差异在于:
1)CyclicBarrier的某个线程运转到某个点上之后,该线程即中止运转,直到一切的线程都抵达了这个点,一切线程才从头运转;CountDownLatch则不是,某线程运转到某个点上之后,仅仅给某个数值-1罢了,该线程持续运转。
2)CyclicBarrier只能唤起一个使命,CountDownLatch能够唤起多个使命。
3)CyclicBarrier可重用,CountDownLatch不可重用,计数值为0该CountDownLatch就不可再用了。java多线程
6、volatile要害字的效果
一个十分重要的问题,是每个学习、应用多线程的Java程序员都必须把握的。了解volatile要害字的效果的条件是要了解Java内存模型,这儿就不讲Java内存模型了,能够拜见第31点,volatile要害字的效果首要有两个:
1)多线程首要围绕可见性和原子性两个特性而翻开,运用volatile要害字润饰的变量,确保了其在多线程之间的可见性,即每次读取到volatile变量,必定是最新的数据。
2)代码底层履行不像咱们看到的高级语言—-Java程序这么简略,它的履行是Java代码–>字节码–>依据字节码履行对应的C/C++代码–>C/C++代码被编译成汇编语言–>和硬件电路交互,现实中,为了获取更好的功能JVM或许会对指令进行重排序,多线程下或许会呈现一些意想不到的问题。运用volatile则会对禁止语义重排序,当然这也必定程度上降低了代码履行功率。
从实践视点而言,volatile的一个重要效果便是和CAS结合,确保了原子性,详细的能够拜见java.util.concurrent.atomic包下的类,比如AtomicInteger,更多概况请点击这儿进行学习。
7、什么是线程安全
又是一个理论的问题,林林总总的答案有许多,我给出一个个人以为解说地最好的:假如你的代码在多线程下履行和在单线程下履行永远都能取得相同的成果,那么你的代码便是线程安全的。
这个问题有值得一提的当地,便是线程安全也是有几个级别的:
1)不可变
像String、Integer、Long这些,都是final类型的类,任何一个线程都改变不了它们的值,要改变除非新创立一个,因而这些不可变目标不需求任何同步手段就能够直接在多线程环境下运用
2)肯定线程安全
不管运转时环境怎样,调用者都不需求额定的同步措施。要做到这一点一般需求支付许多额定的代价,Java中标示自己是线程安全的类,实际上绝大多数都不是线程安全的,不过肯定线程安全的类,Java中也有,比方说CopyOnWriteArrayList、CopyOnWriteArraySet
3)相对线程安全
相对线程安全也便是咱们一般意义上所说的线程安全,像Vector这种,add、remove办法都是原子操作,不会被打断,但也仅限于此,假如有个线程在遍历某个Vector、有个线程一起在add这个Vector,99%的状况下都会呈现ConcurrentModificationException,也便是fail-fast机制。
4)线程非安全
这个就没什么好说的了,ArrayList、LinkedList、HashMap等都是线程非安全的类,点击这儿了解为什么不安全。
8、Java中怎样获取到线程dump文件
死循环、死锁、堵塞、页面翻开慢等问题,打线程dump是最好的解决问题的途径。所谓线程dump也便是线程仓库,获取到线程仓库有两步:
1)获取到线程的pid,能够经过运用jps指令,在Linux环境下还能够运用ps-ef|grepjava
2)打印线程仓库,能够经过运用jstackpid指令,在Linux环境下还能够运用kill-3pid
别的提一点,Thread类供给了一个getStackTrace()办法也能够用于获取线程仓库。这是一个实例办法,因而此办法是和详细线程实例绑定的,每次获取获取到的是详细某个线程当前运转的仓库。
9、一个线程假如呈现了运转时异常会怎样样
假如这个异常没有被捕获的话,这个线程就中止履行了。别的重要的一点是:假如这个线程持有某个某个目标的监视器,那么这个目标监视器会被当即开释
10、怎样在两个线程之间同享数据
经过在线程之间同享目标就能够了,然后经过wait/notify/notifyAll、await/signal/signalAll进行唤起和等候,比方说堵塞行列BlockingQueue便是为线程之间同享数据而设计的
11、sleep办法和wait办法有什么差异
这个问题常问,sleep办法和wait办法都能够用来抛弃CPU必定的时刻,不同点在于假如线程持有某个目标的监视器,sleep办法不会抛弃这个目标的监视器,wait办法会抛弃这个目标的监视器
12、生产者顾客模型的效果是什么
这个问题很理论,可是很重要:
1)经过平衡生产者的生产才能和顾客的消费才能来提升整个体系的运转功率,这是生产者顾客模型最重要的效果
2)解耦,这是生产者顾客模型附带的效果,解耦意味着生产者和顾客之间的联络少,联络越少越能够单独开展而不需求收到彼此的制约
13、ThreadLocal有什么用
简略说ThreadLocal便是一种以空间换时刻的做法,在每个Thread里边维护了一个以开地址法完结的ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不同享,天然就没有线程安全方面的问题了
14、为什么wait()办法和notify()/notifyAll()办法要在同步块中被调用
这是JDK强制的,wait()办法和notify()/notifyAll()办法在调用前都必须先取得目标的锁
15、wait()办法和notify()/notifyAll()办法在抛弃目标监视器时有什么差异
wait()办法和notify()/notifyAll()办法在抛弃目标监视器的时分的差异在于:wait()办法当即开释目标监视器,notify()/notifyAll()办法则会等候线程剩余代码履行结束才会抛弃目标监视器。
16、为什么要运用线程池
避免频繁地创立和毁掉线程,抵达线程目标的重用。别的,运用线程池还能够依据项目灵敏地操控并发的数目。点击这儿学习线程池详解。
17、怎样检测一个线程是否持有目标监视器
我也是在网上看到一道多线程面试题才知道有办法能够判别某个线程是否持有目标监视器:Thread类供给了一个holdsLock(Objectobj)办法,当且仅当目标obj的监视器被某条线程持有的时分才会回来true,留意这是一个static办法,这意味着”某条线程”指的是当前线程。
18、synchronized和ReentrantLock的差异
synchronized是和if、else、for、while相同的要害字,ReentrantLock是类,这是二者的本质差异。已然ReentrantLock是类,那么它就供给了比synchronized更多更灵敏的特性,能够被承继、能够有办法、能够有各式各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:
(1)ReentrantLock能够对获取锁的等候时刻进行设置,这样就避免了死锁
(2)ReentrantLock能够获取各种锁的信息
(3)ReentrantLock能够灵敏地完结多路通知
别的,二者的锁机制其实也是不相同的。ReentrantLock底层调用的是Unsafe的park办法加锁,synchronized操作的应该是目标头中markword,这点我不能确定。
19、ConcurrentHashMap的并发度是什么
ConcurrentHashMap的并发度便是segment的大小,默以为16,这意味着最多一起能够有16条线程操作ConcurrentHashMap,这也是ConcurrentHashMap对Hashtable的最大优势,任何状况下,Hashtable能一起有两条线程获取Hashtable中的数据吗?
20、ReadWriteLock是什么
首先明确一下,不是说ReentrantLock不好,仅仅ReentrantLock某些时分有局限。假如运用ReentrantLock,或许自身是为了避免线程A在写数据、线程B在读数据造成的数据不一致,但这样,假如线程C在读数据、线程D也在读数据,读数据是不会改变数据的,没有必要加锁,可是仍是加锁了,降低了程序的功能。
由于这个,才诞生了读写锁ReadWriteLock。ReadWriteLock是一个读写锁接口,ReentrantReadWriteLock是ReadWriteLock接口的一个详细完结,完结了读写的别离,读锁是同享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提升了读写的功能。
21、FutureTask是什么
这个其实前面有提到过,FutureTask表明一个异步运算的使命。FutureTask里边能够传入一个Callable的详细完结类,能够对这个异步运算的使命的成果进行等候获取、判别是否现已完结、撤销使命等操作。当然,由于FutureTask也是Runnable接口的完结类,所以FutureTask也能够放入线程池中。
22、Linux环境下怎样查找哪个线程运用CPU最长
这是一个比较偏实践的问题,这种问题我觉得挺有意义的。能够这么做:
(1)获取项目的pid,jps或者ps-ef|grepjava,这个前面有讲过
(2)top-H-ppid,顺序不能改变
这样就能够打印出当前的项目,每条线程占用CPU时刻的百分比。留意这儿打出的是LWP,也便是操作体系原生线程的线程号,我笔记本山没有布置Linux环境下的Java工程,因而没有办法截图演示,网友朋友们假如公司是运用Linux环境布置项目的话,能够测验一下。
运用”top-H-ppid”+”jpspid”能够很容易地找到某条占用CPU高的线程的线程仓库,然后定位占用CPU高的原因,一般是由于不当的代码操作导致了死循环。
最终提一点,”top-H-ppid”打出来的LWP是十进制的,”jpspid”打出来的本地线程号是十六进制的,转换一下,就能定位到占用CPU高的线程的当前线程仓库了。
23、Java编程写一个会导致死锁的程序
榜首次看到这个题目,觉得这是一个十分好的问题。许多人都知道死锁是怎样一回事儿:线程A和线程B彼此等候对方持有的锁导致程序无限死循环下去。当然也仅限于此了,问一下怎样写一个死锁的程序就不知道了,这种状况说白了便是不明白什么是死锁,懂一个理论就完事儿了,实践中碰到死锁的问题基本上是看不出来的。
真实了解什么是死锁,这个问题其实不难,几个进程:
1)两个线程里边别离持有两个Object目标:lock1和lock2。这两个lock作为同步代码块的锁;
2)线程1的run()办法中同步代码块先获取lock1的目标锁,Thread.sleep(xxx),时刻不需求太多,50毫秒差不多了,然后接着获取lock2的目标锁。这么做首要是为了避免线程1发动一下子就接连取得了lock1和lock2两个目标的目标锁
3)线程2的run)(办法中同步代码块先获取lock2的目标锁,接着获取lock1的目标锁,当然这时lock1的目标锁现已被线程1锁持有,线程2肯定是要等候线程1开释lock1的目标锁的
这样,线程1″睡觉”睡完,线程2现已获取了lock2的目标锁了,线程1此刻测验获取lock2的目标锁,便被堵塞,此刻一个死锁就形成了。代码就不写了,占的篇幅有点多,Java多线程7:死锁这篇文章里边有,便是上面进程的代码完结。
点击这儿供给了一个死锁的事例。
24、怎样唤醒一个堵塞的线程
假如线程是由于调用了wait()、sleep()或者join()办法而导致的堵塞,能够中止线程,而且经过抛出InterruptedException来唤醒它;假如线程遇到了IO堵塞,力不从心,由于IO是操作体系完结的,Java代码并没有办法直接接触到操作体系。
25、不可变目标对多线程有什么协助
前面有提到过的一个问题,不可变目标确保了目标的内存可见性,对不可变目标的读取不需求进行额定的同步手段,提升了代码履行功率。
26、什么是多线程的上下文切换
多线程的上下文切换是指CPU操控权由一个现已正在运转的线程切换到别的一个就绪并等候获取CPU履行权的线程的进程。
27、假如你提交使命时,线程池行列已满,这时会发生什么
这儿区分一下:
1)假如运用的是无界行列LinkedBlockingQueue,也便是无界行列的话,没关系,持续增加使命到堵塞行列中等候履行,由于LinkedBlockingQueue能够近乎以为是一个无穷大的行列,能够无限存放使命
2)假如运用的是有界行列比如ArrayBlockingQueue,使命首先会被增加到ArrayBlockingQueue中,ArrayBlockingQueue满了,会依据maximumPoolSize的值增加线程数量,假如增加了线程数量仍是处理不过来,ArrayBlockingQueue持续满,那么则会运用拒绝战略RejectedExecutionHandler处理满了的使命,默认是AbortPolicy
28、Java中用到的线程调度算法是什么
抢占式。一个线程用完CPU之后,操作体系会依据线程优先级、线程饥饿状况等数据算出一个总的优先级并分配下一个时刻片给某个线程履行。
29、Thread.sleep(0)的效果是什么
这个问题和上面那个问题是相关的,我就连在一起了。由于Java采用抢占式的线程调度算法,因而或许会呈现某条线程常常获取到CPU操控权的状况,为了让某些优先级比较低的线程也能获取到CPU操控权,能够运用Thread.sleep(0)手动触发一次操作体系分配时刻片的操作,这也是平衡CPU操控权的一种操作。
30、什么是自旋
许多synchronized里边的代码仅仅一些很简略的代码,履行时刻十分快,此刻等候的线程都加锁或许是一种不太值得的操作,由于线程堵塞涉及到用户态和内核态切换的问题。已然synchronized里边的代码履行得十分快,不妨让等候锁的线程不要被堵塞,而是在synchronized的鸿沟做忙循环,这便是自旋。假如做了屡次忙循环发现还没有取得锁,再堵塞,这样或许是一种更好的战略。
31、什么是Java内存模型
Java内存模型界说了一种多线程拜访Java内存的规范。Java内存模型要完整讲不是这儿几句话能说清楚的,我简略总结一下Java内存模型的几部分内容:
1)Java内存模型将内存分为了主内存和作业内存。类的状况,也便是类之间同享的变量,是存储在主内存中的,每次Java线程用到这些主内存中的变量的时分,会读一次主内存中的变量,并让这些内存在自己的作业内存中有一份拷贝,运转自己线程代码的时分,用到这些变量,操作的都是自己作业内存中的那一份。在线程代码履行结束之后,会将最新的值更新到主内存中去
2)界说了几个原子操作,用于操作主内存和作业内存中的变量
3)界说了volatile变量的运用规矩
4)happens-before,即先行发生原则,界说了操作A必定先行发生于操作B的一些规矩,比如在同一个线程内操控流前面的代码必定先行发生于操控流后面的代码、一个开释锁unlock的动作必定先行发生于后面关于同一个锁进行确定lock的动作等等,只需契合这些规矩,则不需求额定做同步措施,假如某段代码不契合一切的happens-before规矩,则这段代码必定是线程非安全的
32、什么是CAS
CAS,全称为CompareandSwap,即比较-替换。假定有三个操作数:内存值V、旧的预期值A、要修正的值B,当且仅当预期值A和内存值V相一起,才会将内存值修正为B并回来true,不然什么都不做并回来false。当然CAS必定要volatile变量合作,这样才能确保每次拿到的变量是主内存中最新的那个值,不然旧的预期值A对某条线程来说,永远是一个不会变的值A,只需某次CAS操作失利,永远都不或许成功。更多CAS概况请点击这儿学习。
33、什么是达观锁和失望锁
1)达观锁:就像它的姓名相同,关于并发间操作发生的线程安全问题持达观状况,达观锁以为竞赛不总是会发生,因而它不需求持有锁,将比较-替换这两个动作作为一个原子操作测验去修正内存中的变量,假如失利则表明发生冲突,那么就应该有相应的重试逻辑。
2)失望锁:仍是像它的姓名相同,关于并发间操作发生的线程安全问题持失望状况,失望锁以为竞赛总是会发生,因而每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。
点击这儿了解更多达观锁与失望锁概况。
34、什么是AQS
简略说一下AQS,AQS全称为AbstractQueuedSychronizer,翻译过来应该是抽象行列同步器。
假如说java.util.concurrent的根底是CAS的话,那么AQS便是整个Java并发包的中心了,ReentrantLock、CountDownLatch、Semaphore等等都用到了它。AQS实际上以双向行列的形式衔接一切的Entry,比方说ReentrantLock,一切等候的线程都被放在一个Entry中并连成双向行列,前面一个线程运用ReentrantLock好了,则双向行列实际上的榜首个Entry开端运转。
AQS界说了对双向行列一切的操作,而只开放了tryLock和tryRelease办法给开发者运用,开发者能够依据自己的完结重写tryLock和tryRelease办法,以完结自己的并发功能。
35、单例形式的线程安全性
老生常谈的问题了,首先要说的是单例形式的线程安全意味着:某个类的实例在多线程环境下只会被创立一次出来。单例形式有许多种的写法,我总结一下:
1)饿汉式单例形式的写法:线程安全
2)懒汉式单例形式的写法:非线程安全
3)双检锁单例形式的写法:线程安全
36、Semaphore有什么效果
Semaphore便是一个信号量,它的效果是约束某段代码块的并发数。Semaphore有一个结构函数,能够传入一个int型整数n,表明某段代码最多只需n个线程能够拜访,假如超出了n,那么请等候,等到某个线程履行结束这段代码块,下一个线程再进入。由此能够看出假如Semaphore结构函数中传入的int型整数n=1,相当于变成了一个synchronized了。
37、Hashtable的size()办法中分明只需一条句子”returncount”,为什么还要做同步?
这是我之前的一个困惑,不知道大家有没有想过这个问题。某个办法中假如有多条句子,而且都在操作同一个类变量,那么在多线程环境下不加锁,势必会引发线程安全问题,这很好了解,可是size()办法分明只需一条句子,为什么还要加锁?
关于这个问题,在慢慢地作业、学习中,有了了解,首要原因有两点:
1)同一时刻只能有一条线程履行固定类的同步办法,可是关于类的非同步办法,能够多条线程一起拜访。所以,这样就有问题了,或许线程A在履行Hashtable的put办法增加数据,线程B则能够正常调用size()办法读取Hashtable中当前元素的个数,那读取到的值或许不是最新的,或许线程A增加了完了数据,可是没有对size++,线程B就现已读取size了,那么关于线程B来说读取到的size必定是不精确的。而给size()办法加了同步之后,意味着线程B调用size()办法只需在线程A调用put办法结束之后才能够调用,这样就确保了线程安全性
2)CPU履行代码,履行的不是Java代码,这点很要害,必定得记住。Java代码最终是被翻译成机器码履行的,机器码才是真实能够和硬件电路交互的代码。即便你看到Java代码只需一行,乃至你看到Java代码编译之后生成的字节码也只需一行,也不意味着关于底层来说这句句子的操作只需一个。一句”returncount”假定被翻译成了三句汇编句子履行,一句汇编句子和其机器码做对应,完全或许履行完榜首句,线程就切换了。
38、线程类的结构办法、静态块是被哪个线程调用的
这是一个十分刁钻和狡猾的问题。请记住:线程类的结构办法、静态块是被new这个线程类所在的线程所调用的,而run办法里边的代码才是被线程自身所调用的。
假如说上面的说法让你感到困惑,那么我举个比如,假定Thread2中new了Thread1,main函数中new了Thread2,那么:
1)Thread2的结构办法、静态块是main线程调用的,Thread2的run()办法是Thread2自己调用的
2)Thread1的结构办法、静态块是Thread2调用的,Thread1的run()办法是Thread1自己调用的
39、同步办法和同步块,哪个是更好的选择
同步块,这意味着同步块之外的代码是异步履行的,这比同步整个办法更提升代码的功率。请知道一条原则:同步的规模越小越好。
借着这一条,我额定提一点,虽然同步的规模越少越好,可是在Java虚拟机中仍是存在着一种叫做锁粗化的优化办法,这种办法便是把同步规模变大。这是有用的,比方说StringBuffer,它是一个线程安全的类,天然最常用的append()办法是一个同步办法,咱们写代码的时分会重复append字符串,这意味着要进行重复的加锁->解锁,这对功能晦气,由于这意味着Java虚拟机在这条线程上要重复地在内核态和用户态之间进行切换,因而Java虚拟机会将屡次append办法调用的代码进行一个锁粗化的操作,将屡次的append的操作扩展到append办法的头尾,变成一个大的同步块,这样就削减了加锁–>解锁的次数,有效地提升了代码履行的功率。
40、高并发、使命履行时刻短的事务怎样运用线程池?并发不高、使命履行时刻长的事务怎样运用线程池?并发高、事务履行时刻长的事务怎样运用线程池?
这是我在并发编程网上看到的一个问题,把这个问题放在最终一个,希望每个人都能看到而且考虑一下,由于这个问题十分好、十分实际、十分专业。关于这个问题,个人观点是:
1)高并发、使命履行时刻短的事务,线程池线程数能够设置为CPU核数+1,削减线程上下文的切换
2)并发不高、使命履行时刻长的事务要区分开看:
a)假如是事务时刻长会集在IO操作上,也便是IO密集型的使命,由于IO操作并不占用CPU,所以不要让一切的CPU闲下来,能够加大线程池中的线程数目,让CPU处理更多的事务
b)假如是事务时刻长会集在核算操作上,也便是核算密集型使命,这个就没办法了,和(1)相同吧,线程池中的线程数设置得少一些,削减线程上下文的切换
c)并发高、事务履行时刻长,解决这种类型使命的要害不在于线程池而在于全体架构的设计,看看这些事务里边某些数据是否能做缓存是榜首步,增加服务器是第二步,至于线程池的设置,设置参阅其他有关线程池的文章。最终,事务履行时刻长的问题,也或许需求剖析一下,看看能不能运用中间件对使命进行拆分和解耦。

未经允许不得转载:IT技术网站 » java多线程(面试题及答案)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载