一、多线程有什么用? java
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,分别创建程序模型,并经过多线程分别运行这几个任务,那就简单不少了。算法
二、线程和进程的区别是什么? 数据库
进程和线程的主要差异在于它们是不一样的操做系统资源管理方式。
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不一样执行路径。
线程有本身的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,因此多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。
但对于一些要求同时进行而且又要共享某些变量的并发操做,只能用线程,不能用进程。
三、Java 实现线程有哪几种方式? 编程
一、继承 Thread 类实现多线程
二、实现 Runnable 接口方式实现多线程
三、使用 ExecutorService、Callable、Future 实现有返回结果的多线程
四、启动线程方法 start()和 run()有什么区别? 缓存
只有调用了 start()方法,才会表现出多线程的特性,不一样线程的 run()方法里面的代码交替执行。若是只是调用 run()方法,那么代码仍是同步执行的,必须等待一个线程的 run()方法里面的代码所有执行完毕以后,另一个线程才能够执行其 run()方法里面的代码。
五、怎么终止一个线程?如何优雅地终止线程? 安全
六、一个线程的生命周期有哪几种状态?它们之间如何流转的? 服务器
NEW:毫无疑问表示的是刚建立的线程,尚未开始启动。
RUNNABLE: 表示线程已经触发 start()方式调用,线程正式启动,线程处于运行中状态。
BLOCKED:表示线程阻塞,等待获取锁,如碰到 synchronized、lock 等关键字等占用临界区的状况,一旦获取到锁就进行 RUNNABLE 状态继续运行。
WAITING:表示线程处于无限制等待状态,等待一个特殊的事件来从新唤醒,如经过wait()方法进行等待的线程等待一个 notify()或者 notifyAll()方法,经过 join()方法进行等待的线程等待目标线程运行结束而唤醒,一旦经过相关事件唤醒线程,线程就进入了 RUNNABLE 状态继续运行。
TIMED_WAITING:表示线程进入了一个有时限的等待,如 sleep(3000),等待 3 秒后线程从新进行 RUNNABLE 状态继续运行。
TERMINATED:表示线程执行完毕后,进行终止状态。须要注意的是,一旦线程经过 start 方法启动后就不再能回到初始 NEW 状态,线程终止后也不能再回到 RUNNABLE 状态
七、线程中的 wait()和 sleep()方法有什么区别? 多线程
这个问题常问,sleep 方法和 wait 方法均可以用来放弃 CPU 必定的时间,不一样点在于若是线程持有某个对象的监视器,sleep 方法不会放弃这个对象的监视器,wait 方法会放弃这个对象的监视器
八、多线程同步有哪几种方法?
Synchronized 关键字,Lock 锁实现,分布式锁等。
九、什么是死锁?如何避免死锁?
十、多线程之间如何进行通讯?
十一、线程怎样拿到返回结果?
十二、violatile 关键字的做用?
一个很是重要的问题,是每一个学习、应用多线程的 Java 程序员都必须掌握的。理解 volatile关键字的做用的前提是要理解 Java 内存模型,这里就不讲 Java 内存模型了,能够参见第31 点,volatile 关键字的做用主要有两个:
一、多线程主要围绕可见性和原子性两个特性而展开,使用 volatile 关键字修饰的变量,保证了其在多线程之间的可见性,即每次读取到 volatile 变量,必定是最新的数据
二、代码底层执行不像咱们看到的高级语言----Java 程序这么简单,它的执行是 Java 代码-->字节码-->根据字节码执行对应的 C/C++代码-->C/C++代码被编译成汇编语言-->和硬件电路交互,现实中,为了获取更好的性能 JVM 可能会对指令进行重排序,多线程下可能会出现一些意想不到的问题。使用 volatile 则会对禁止语义重排序,固然这也必定程度上下降了代码执行效率从实践角度而言,volatile 的一个重要做用就是和 CAS 结合,保证了原子性,详细的能够参见 java.util.concurrent.atomic 包下的类,好比 AtomicInteger。
1三、新建 T一、T二、T3 三个线程,如何保证它们按顺序执行?
1四、怎么控制同一时间只有 3 个线程运行?
1五、为何要使用线程池?
咱们知道不用线程池的话,每一个线程都要经过 new Thread(xxRunnable).start()的方式来建立并运行一个线程,线程少的话这不会是问题,而真实环境可能会开启多个线程让系统和程序达到最佳效率,当线程数达到必定数量就会耗尽系统的 CPU 和内存资源,也会形成 GC频繁收集和停顿,由于每次建立和销毁一个线程都是要消耗系统资源的,若是为每一个任务都建立线程这无疑是一个很大的性能瓶颈。因此,线程池中的线程复用极大节省了系统资源,当线程一段时间再也不有任务处理时它也会自动销毁,而不会长驻内存。
1六、经常使用的几种线程池并讲讲其中的工做原理。
什么是线程池? 很简单,简单看名字就知道是装有线程的池子,咱们能够把要执行的多线程交给线程池来处理,和链接池的概念同样,经过维护必定数量的线程池来达到多个线程的复用。
线程池的好处 咱们知道不用线程池的话,每一个线程都要经过 new Thread(xxRunnable).start()的方式来建立并运行一个线程,线程少的话这不会是问题,而真实环境可能会开启多个线程让系统和程序达到最佳效率,当线程数达到必定数量就会耗尽系统的 CPU 和内存资源,也会形成 GC频繁收集和停顿,由于每次建立和销毁一个线程都是要消耗系统资源的,若是为每一个任务都建立线程这无疑一个很大的性能瓶颈。因此,线程池中的线程复用极大节省了系统资源,当线程一段时间再也不有任务处理时它也会自动销毁,而不会长驻内存。
线程池核心类 在 java.util.concurrent 包中咱们能找到线程池的定义,其中 ThreadPoolExecutor 是咱们线程池核心类,首先看看线程池类的主要参数有哪些。
如何提交线程 如能够先随便定义一个固定大小的线程池 ExecutorService es = Executors.newFixedThreadPool(3);
提交一个线程 es.submit(xxRunnble); es.execute(xxRunnble);
submit 和 execute 分别有什么区别呢? execute 没有返回值,若是不须要知道线程的结果就使用 execute 方法,性能会好不少。submit 返回一个 Future 对象,若是想知道线程结果就使用 submit 提交,并且它能在主线程中经过 Future 的 get 方法捕获线程中的异常。
如何关闭线程池 es.shutdown(); 再也不接受新的任务,以前提交的任务等执行结束再关闭线程池。 es.shutdownNow(); 再也不接受新的任务,试图中止池中的任务再关闭线程池,返回全部未处理的线程 list 列表。
1七、线程池启动线程 submit()和 execute()方法有什么不一样?
execute 没有返回值,若是不须要知道线程的结果就使用 execute 方法,性能会好不少。submit 返回一个 Future 对象,若是想知道线程结果就使用 submit 提交,并且它能在主线程中经过 Future 的 get 方法捕获线程中的异常。
1八、CyclicBarrier 和 CountDownLatch 的区别?
两个看上去有点像的类,都在 java.util.concurrent 下,均可以用来表示代码运行到某个点上,两者的区别在于:
一、CyclicBarrier 的某个线程运行到某个点上以后,该线程即中止运行,直到全部的线程都到达了这个点,全部线程才从新运行;CountDownLatch 则不是,某线程运行到某个点上以后,只是给某个数值-1 而已,该线程继续运行
二、CyclicBarrier 只能唤起一个任务,CountDownLatch 能够唤起多个任务
三、CyclicBarrier 可重用,CountDownLatch 不可重用,计数值为 0 该 CountDownLatch就不可再用了
1九、什么是活锁、饥饿、无锁、死锁?
死锁、活锁、饥饿是关于多线程是否活跃出现的运行阻塞障碍问题,若是线程出现了 这三种状况,即线程再也不活跃,不能再正常地执行下去了。
死锁 死锁是多线程中最差的一种状况,多个线程相互占用对方的资源的锁,而又相互等对方释放锁,此时若无外力干预,这些线程则一直处理阻塞的假死状态,造成死锁。 举个例子,A 同窗抢了 B 同窗的钢笔,B 同窗抢了 A 同窗的书,两我的都相互占用对方的东西,都在让对方先还给本身本身再还,这样一直争执下去等待对方还而又得不到解决,老师知道此过后就让他们相互还给对方,这样在外力的干预下他们才解决,固然这只是个例子没有老师他们也能很好解决,计算机不像人若是发现这种状况没有外力干预仍是会一直阻塞下去的。
活锁 活锁这个概念你们应该不多有人据说或理解它的概念,而在多线程中这确实存在。活锁偏偏与死锁相反,死锁是你们都拿不到资源都占用着对方的资源,而活锁是拿到资源却又相互释放不执行。当多线程中出现了相互谦让,都主动将资源释放给别的线程使用,这样这个资源在多个线程之间跳动而又得不到执行,这就是活锁。
饥饿 咱们知道多线程执行中有线程优先级这个东西,优先级高的线程可以插队并优先执行,这样若是优先级高的线程一直抢占优先级低线程的资源,致使低优先级线程没法获得执行,这就是饥饿。固然还有一种饥饿的状况,一个线程一直占着一个资源不放而致使其余线程得不到执行,与死锁不一样的是饥饿在之后一段时间内仍是可以获得执行的,如那个占用资源的线程结束了并释放了资源。
无锁 无锁,即没有对资源进行锁定,即全部的线程都能访问并修改同一个资源,但同时只有一个线程能修改为功。无锁典型的特色就是一个修改操做在一个循环内进行,线程会不断的尝试修改共享资源,若是没有冲突就修改为功并退出不然就会继续下一次循环尝试。因此,若是有多个线程修改同一个值一定会有一个线程能修改为功,而其余修改失败的线程会不断重试直到修改为功。以前的文章我介绍过 JDK 的 CAS 原理及应用便是无锁的实现。 能够看出,无锁是一种很是良好的设计,它不会出现线程出现的跳跃性问题,锁使用不当确定会出现系统性能问题,虽然无锁没法全面代替有锁,但无锁在某些场合下是很是高效的。
20、什么是原子性、可见性、有序性?
原子性、可见性、有序性是多线程编程中最重要的几个知识点,因为多线程状况复杂,如何让每一个线程能看到正确的结果,这是很是重要的。
原子性 原子性是指一个线程的操做是不能被其余线程打断,同一时间只有一个线程对一个变量进行操做。在多线程状况下,每一个线程的执行结果不受其余线程的干扰,好比说多个线程同时对同一个共享成员变量 n++100 次,若是 n 初始值为 0,n 最后的值应该是 100,因此说它们是互不干扰的,这就是传说的中的原子性。但 n++并非原子性的操做,要使用 AtomicInteger 保证原子性。
可见性 可见性是指某个线程修改了某一个共享变量的值,而其余线程是否能够看见该共享变量修改后的值。在单线程中确定不会有这种问题,单线程读到的确定都是最新的值,而在多线程编程中就不必定了。 每一个线程都有本身的工做内存,线程先把共享变量的值从主内存读到工做内存,造成一个副本,当计算完后再把副本的值刷回主内存,从读取到最后刷回主内存这是一个过程,当还没刷回主内存的时候这时候对其余线程是不可见的,因此其余线程从主内存读到的值是修改以前的旧值。像 CPU 的缓存优化、硬件优化、指令重排及对 JVM 编译器的优化,都会出现可见性的问题。
有序性 咱们都知道程序是按代码顺序执行的,对于单线程来讲确实是如此,但在多线程状况下就不是如此了。为了优化程序执行和提升 CPU 的处理性能,JVM 和操做系统都会对指令进行重排,也就说前面的代码并不必定都会在后面的代码前面执行,即后面的代码可能会插到前面的代码以前执行,只要不影响当前线程的执行结果。因此,指令重排只会保证当前线程执行结果一致,但指令重排后势必会影响多线程的执行结果。虽然重排序优化了性能,但也是会遵照一些规则的,并不能随便乱排序,只是重排序会影响多线程执行的结果。
什么是守护线程? 与守护线程相对应的就是用户线程,守护线程就是守护用户线程,当用户线程所有执行完结束以后,守护线程才会跟着结束。也就是守护线程必须伴随着用户线程,若是一个应用内只存在一个守护线程,没有用户线程,守护线程天然会退出。
2二、一个线程运行时发生异常会怎样?
若是异常没有被捕获该线程将会中止执行。Thread.UncaughtExceptionHandler 是用于处理未捕获异常形成线程忽然中断状况的一个内嵌接口。当一个未捕获异常将形成线程中断的时 候 JVM 会 使 用 Thread.getUncaughtExceptionHandler() 来 查 询 线 程 的UncaughtExceptionHandler 并 将 线 程 和 异 常 做 为 参 数 传 递 给 handler 的uncaughtException()方法进行处理。
2三、线程 yield()方法有什么用?
Yield 方法能够暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。它是一个静态方法并且只保证当前线程放弃 CPU 占用而不能保证使其它线程必定能占用 CPU,执行yield()的线程有可能在进入到暂停状态后立刻又被执行。
2四、什么是重入锁?
所谓重入锁,指的是以线程为单位,当一个线程获取对象锁以后,这个线程能够再次获取本对象上的锁,而其余的线程是不能够的。
2五、Synchronized 有哪几种用法?
2六、Fork/Join 框架是干什么的?
2七、线程数过多会形成什么异常?
2八、说说线程安全的和不安全的集合。
Java 中平时用的最多的 Map 集合就是 HashMap 了,它是线程不安全的。
看下面两个场景:
一、当用在方法内的局部变量时,局部变量属于当前线程级别的变量,其余线程访问不了,因此这时也不存在线程安全不安全的问题了。
二、当用在单例对象成员变量的时候呢?这时候多个线程过来访问的就是同一个HashMap 了,对同个 HashMap 操做这时候就存在线程安全的问题了。
2九、什么是 CAS 算法?在多线程中有哪些应用。
CAS,全称为 Compare and Swap,即比较-替换。假设有三个操做数:内存值 V、旧的预期值 A、要修改的值 B,当且仅当预期值 A 和内存值 V 相同时,才会将内存值修改成 B 并返回 true,不然什么都不作并返回 false。固然 CAS 必定要 volatile 变量配合,这样才能保证每次拿到的变量是主内存中最新的那个值,不然旧的预期值 A 对某条线程来讲,永远是一个不会变的值 A,只要某次 CAS 操做失败,永远都不可能成功。java.util.concurrent.atomic 包下面的 Atom****类都有 CAS 算法的应用。
30、怎么检测一个线程是否拥有锁?
java.lang.Thread#holdsLock 方法
3一、Jdk 中排查多线程问题用什么命令?
3二、线程同步须要注意什么?
一、尽可能缩小同步的范围,增长系统吞吐量。
二、分布式同步锁无心义,要使用分布式锁。
三、防止死锁,注意加锁顺序。
3三、线程 wait()方法使用有什么前提?
3四、Fork/Join 框架使用有哪些要注意的地方?
若是任务拆解的很深,系统内的线程数量堆积,致使系统性能性能严重降低;
若是函数的调用栈很深,会致使栈内存溢出;
3五、线程之间如何传递数据?
通 过 在 线 程 之 间 共 享 对 象 就 可 以 了 , 然 后 通 过 wait/notify/notifyAll 、await/signal/signalAll 进行唤起和等待,比方说阻塞队列 BlockingQueue 就是为线程之间共享数据而设计的
3六、保证"可见性"有哪几种方式?
3七、说几个经常使用的 Lock 接口实现锁。
ReentrantLock、ReadWriteLock
3八、ThreadLocal 是什么?有什么应用场景?
ThreadLocal 的做用是提供线程内的局部变量,这种变量在线程的生命周期内起做用,减小同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。用来解决数据库链接、Session 管理等。
3九、ReadWriteLock 有什么用?
ReadWriteLock 是一个读写锁接口,ReentrantReadWriteLock 是 ReadWriteLock 接口的一个具体实现,实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提高了读写的性能。
40、FutureTask 是什么?
FutureTask 表示一个异步运算的任务,FutureTask 里面能够传入一个 Callable 的具体实现类,能够对这个异步运算的任务的结果进行等待获取、判断是否已经完成、取消任务等操做。
4一、怎么唤醒一个阻塞的线程?
若是线程是由于调用了 wait()、sleep()或者 join()方法而致使的阻塞,能够中断线程,而且经过抛出 InterruptedException 来唤醒它;若是线程遇到了 IO 阻塞,无能为力,由于 IO是操做系统实现的,Java 代码并无办法直接接触到操做系统。
4二、不可变对象对多线程有什么帮助?
不可变对象保证了对象的内存可见性,对不可变对象的读取不须要进行额外的同步手段,提 升了代码执行效率。
4三、多线程上下文切换是什么意思?
多线程的上下文切换是指 CPU 控制权由一个已经正在运行的线程切换到另一个就绪并等待获取 CPU 执行权的线程的过程。
4四、Java 中用到了什么线程调度算法?
抢占式。一个线程用完 CPU 以后,操做系统会根据线程优先级、线程饥饿状况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。
4五、Thread.sleep(0)的做用是什么?
因为 Java 采用抢占式的线程调度算法,所以可能会出现某条线程经常获取到 CPU 控制权的状况,为了让某些优先级比较低的线程也能获取到 CPU 控制权,可使用 Thread.sleep(0)手动触发一次操做系统分配时间片的操做,这也是平衡 CPU 控制权的一种操做。
4六、什么是乐观锁和悲观锁?
乐观锁:就像它的名字同样,对于并发间操做产生的线程安全问题持乐观状态,乐观锁认为竞争不老是会发生,所以它不须要持有锁,将比较-替换这两个动做做为一个原子操做尝试去修改内存中的变量,若是失败则表示发生冲突,那么就应该有相应的重试逻辑。
悲观锁:仍是像它的名字同样,对于并发间操做产生的线程安全问题持悲观状态,悲观锁认为竞争老是会发生,所以每次对某资源进行操做时,都会持有一个独占的锁,就像synchronized,无论三七二十一,直接上了锁就操做资源了。
4七、Hashtable 的 size()方法为何要作同步?
同一时间只能有一条线程执行固定类的同步方法,可是对于类的非同步方法,能够多条线程同时访问。因此,这样就有问题了,可能线程 A 在执行 Hashtable 的 put 方法添加数据,线程 B 则能够正常调用 size()方法读取 Hashtable 中当前元素的个数,那读取到的值可能不是最新的,可能线程 A 添加了完了数据,可是没有对 size++,线程 B 就已经读取 size了,那么对于线程 B 来讲读取到的 size 必定是不许确的。而给 size()方法加了同步以后,意味着线程 B 调用 size()方法只有在线程 A 调用 put 方法完毕以后才能够调用,这样就保证了线程安全性CPU 执行代码,执行的不是 Java 代码,这点很关键,必定得记住。Java 代码最终是被翻译成机器码执行的,机器码才是真正能够和硬件电路交互的代码。即便你看到 Java 代码只有一行,甚至你看到 Java 代码编译以后生成的字节码也只有一行,也不意味着对于底层来讲这句语句的操做只有一个。一句"return count"假设被翻译成了三句汇编语句执行,一句汇编语句和其机器码作对应,彻底可能执行完第一句,线程就切换了。
4八、同步方法和同步块,哪一种更好?
同步块,这意味着同步块以外的代码是异步执行的,这比同步整个方法更提高代码的效率。请知道一条原则:同步的范围越小越好。
4九、什么是自旋锁?
自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其余线程改变时 才能进入临界区。
50、Runnable 和 Thread 用哪一个好?
Java 不支持类的多重继承,但容许你实现多个接口。因此若是你要继承其余类,也为了减 少类之间的耦合性,Runnable 会更好。
5一、Java 中 notify 和 notifyAll 有什么区别?
notify()方法不能唤醒某个具体的线程,因此只有一个线程在等待的时候它才有用武之地。而 notifyAll()唤醒全部线程并容许他们争夺锁确保了至少有一个线程能继续运行。
5二、为何 wait/notify/notifyAll 这些方法不在 thread 类里面?
这是个设计相关的问题,它考察的是面试者对现有系统和一些广泛存在但看起来不合理的事物的见解。回答这些问题的时候,你要说明为何把这些方法放在 Object 类里是有意义的,还有不把它放在 Thread 类里的缘由。一个很明显的缘由是 JAVA 提供的锁是对象级的而不是线程级的,每一个对象都有锁,经过线程得到。若是线程须要等待某些锁那么调用对象中的wait()方法就有意义了。若是 wait()方法定义在 Thread 类中,线程正在等待的是哪一个锁就不明显了。简单的说,因为 wait,notify 和 notifyAll 都是锁级别的操做,因此把他们定义在 Object 类中由于锁属于对象。
5三、为何 wait 和 notify 方法要在同步块中调用?
主 要 是 因 为 Java API 强 制 要 求 这 样 作 , 如 果 你 不 这 么 作 , 你 的 代 码 会 抛 出IllegalMonitorStateException 异常。还有一个缘由是为了不 wait 和 notify 之间产生竞态条件。
5四、为何你应该在循环中检查等待条件?
处于等待状态的线程可能会收到错误警报和伪唤醒,若是不在循环中检查等待条件,程序就会在没有知足结束条件的状况下退出。所以,当一个等待线程醒来时,不能认为它原来的等待状态仍然是有效的,在 notify()方法调用以后和等待线程醒来以前这段时间它可能会改变。这就是在循环中使用 wait()方法效果更好的缘由,你能够在 Eclipse 中建立模板调用 wait和 notify 试一试。
5五、Java 中堆和栈有什么不一样?
每一个线程都有本身的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是全部线程共享的一片公用内存区域。对象都在堆里建立,为了提高效率线程会从堆中弄一个缓存到本身的栈,若是多个线程使用该变量就可能引起问题,这时 volatile 变量就能够发挥做用了,它要求线程从主存中读取变量的值。
5六、你如何在 Java 中获取线程堆栈?
对于不一样的操做系统,有多种方法来得到 Java 进程的线程堆栈。当你获取线程堆栈时,JVM会把全部线程的状态存到日志文件或者输出到控制台。在 Windows 你可使用 Ctrl +Break 组合键来获取线程堆栈,Linux 下用 kill -3 命令。你也能够用 jstack 这个工具来获取,它对线程 id 进行操做,你能够用 jps 这个工具找到 id。
5七、如何建立线程安全的单例模式?
单例模式即一个 JVM 内存中只存在一个类的对象实例分类
一、懒汉式 类加载的时候就建立实例
二、饿汉式 使用的时候才建立实例
5八、什么是阻塞式方法?
阻塞式方法是指程序会一直等待该方法完成期间不作其余事情,ServerSocket 的 accept()方法就是一直等待客户端链接。这里的阻塞是指调用结果返回以前,当前线程会被挂起,直到获得结果以后才会返回。此外,还有异步和非阻塞式方法在任务完成前就返回。
5九、提交任务时线程池队列已满会时发会生什么?
当线程数小于最大线程池数 maximumPoolSize 时就会建立新线程来处理,而线程数大于等于最大线程池数 maximumPoolSize 时就会执行拒绝策略。