Logo
Section 1 / 8

测验1

测试你对进程线程、线程池与并发任务的理解

检查点

测验1

测试你对进程线程、线程池与并发任务的理解

问题 #1

进程和线程之间有哪些主要区别?

  • 一个进程可以包含多个线程,而一个线程只能属于一个进程。

  • 线程比进程更轻量,占用的系统资源也比进程少。

  • 线程自身拥有一些私有状态,但同一进程内的线程可以共享该进程分配到的资源,包括内存地址空间。

问题 #2

根据以下代码,你能指出程序员遗漏了什么吗?

1 void defectiveCode(final int n) throws ExecutionException, InterruptedException { 2 3 ExecutorService threadPool = Executors.newFixedThreadPool(5); 4 5 Callable<Void> sumTask = new Callable<Void>() { 6 7 public Void call() throws Exception { 8 System.out.println("Running"); 9 return null; 10 } 11 }; 12 13 threadPool.submit(sumTask).get(); 14 }

上述代码遗漏了对执行器线程池的关闭(shutdown)操作。当线程池被创建时,会同时启动5个工作线程。如果在退出主方法前没有显式关闭线程池,JVM也不会正常退出,因为它会等待所有工作线程完成任务——而这些线程默认不是守护线程(daemon)。例如,运行下面的代码片段就会出现超时无法结束的情况。

1import java.util.concurrent.Callable; 2import java.util.concurrent.ExecutionException; 3import java.util.concurrent.ExecutorService; 4import java.util.concurrent.Executors; 5import java.util.concurrent.Future; 6 7class Demonstration { 8 public static void main( String args[] ) throws Exception { 9 ExecutorService threadPool = Executors.newFixedThreadPool(5); 10 11 Callable<Void> someTask = new Callable<Void>() { 12 13 public Void call() throws Exception { 14 System.out.println("Running"); 15 return null; 16 } 17 }; 18 19 threadPool.submit(someTask).get(); 20 21 System.out.println( "Program Exiting" ); 22 } 23}

尽管两条打印语句都会输出,程序仍会因执行超时而无法正常终止。你只需在方法末尾添加threadPool.shutdown()即可修复此问题。

问题 #3

当调用getWorking方法时,你认为哪个compute()方法会被调用?

1class ThreadsWithLambda { 2 3 public void getWorking() throws Exception { 4 compute(() -> "done"); 5 } 6 7 void compute(Runnable r) { 8 System.out.println("Runnable invoked"); 9 r.run(); 10 } 11 12 <T> T compute(Callable<T> c) throws Exception { 13 System.out.println("Callable invoked"); 14 return c.call(); 15 } 16}

lambda表达式返回字符串“done”,因此编译器会将该调用匹配到第二个compute方法,此时lambda表达式被视为Callable接口类型。你可以运行以下代码片段并查看输出结果来验证这一点。

1import java.util.concurrent.Callable; 2 3class Demonstration { 4 public static void main( String args[] ) throws Exception{ 5 (new LambdaTargetType()).getWorking(); 6 } 7} 8 9class LambdaTargetType { 10 11 public void getWorking() throws Exception { 12 compute(() -> "done"); 13 } 14 15 void compute(Runnable r) { 16 System.out.println("Runnable invoked"); 17 r.run(); 18 } 19 20 <T> T compute(Callable<T> c) throws Exception { 21 System.out.println("Callable invoked"); 22 return c.call(); 23 } 24}

问题 #4

在Java中,有哪些方式可以表示可由线程执行的任务?

问题 #5

给定以下代码片段,innerThread会打印多少次消息?

1 public void spawnThread() { 2 3 Thread innerThread = new Thread(new Runnable() { 4 5 public void run() { 6 7 for (int i = 0; i < 100; i++) { 8 System.out.println("I am a new thread !"); 9 } 10 } 11 }); 12 13 innerThread.start(); 14 System.out.println("Main thread exiting"); 15 }

问题 #6

给定以下代码片段,innerThread会打印多少条消息?

1 public void spawnDaemonThread() { 2 3 Thread innerThread = new Thread(new Runnable() { 4 5 public void run() { 6 7 for (int i = 0; i < 100; i++) { 8 System.out.println("I am a daemon thread !"); 9 } 10 } 11 }); 12 13 innerThread.setDaemon(true); 14 innerThread.start(); 15 System.out.println("Main thread exiting"); 16 }

问题 #7

假设你的程序运行恰好需要10分钟。学习本课程后,你希望引入并发来提升性能。然而,你在程序中仅使用了两个线程。在其他条件不变的情况下,理论上你的优化后程序最短可能运行多长时间?

问题 #8

一个串行程序被重构以利用多线程,但程序员只使用了两个线程。工作负载被划分成两部分,其中一个线程完成任务所需时间是另一个线程的9倍。那么该程序相对于原始串行版本的理论最大加速比是多少(以百分比形式表示)?

Quiz

单选题

在Java中,有哪些方式可以表示可由线程执行的任务?

1 / 1

Java 并发参考

测验2