日常Java练习题(每天进步一点点系列)

简介: 日常Java练习题(每天进步一点点系列)

1、时间片调度属于____,多线程分别绑定CPU属于____。

正确答案:B

A 并发,并发

B 并发,并行

C 并行,并行

D 并行,并发


题解:

1、 并发是同时处理很多事情, 并行是同时执行很多事情; 并发的关键是你有处理多个任务的能力,不一定要同时。 并行的关键是你有同时处理多个任务的能力。 比如说吃饭的时候来电话了,吃饭和打电话是两件事。 串行:必须吃完饭,才去接电话; 并行:一边吃饭,一边打电话; 并发:先吃饭,电话来了接电话(不一定吃完饭),电话结束再去吃饭。

2、 并发:同一时刻只能有一个处于执行状态,但是它们交换着进行,因此在同一段时间内可看做是同时进行的。 并行:同一时刻多个同时进行,多路线进行。


2、下面关于并行和并发的区别,说法错误的是?

正确答案:C

A 并发计算是一种程序计算的形式,在系统中,至少有两个以上的计算在同时运作,计算结果可能同时发生

B 并行计算指许多指令得以同时进行的计算模式。在同时进行的前提下,可以将计算的过程分解成小部份,之后以并发方式来加以解决

C 并行是同时发生的多个并发事件,并发事件之间一定要同一时刻发生

D 并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生


题解:

1、 C 你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。 你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。 你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。 并发的关键是你有处理多个任务的能力,不一定要同时。 并行的关键是你有同时处理多个任务的能力。 所以我认为它们最关键的点就是:是否是『同时』。

2、 并发和并行的区别就是一个处理器同时处理多个任务和多个处理器或者是多核的处理器同时处理多个不同的任务。 并发性(concurrency),又称共行性,是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。 并行(parallelism)是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。


3、在win32平台下,以下哪种方式无法实现进程同步?

正确答案:A

A Critical Section

B Event

C Mutex

D Semaphore


题解:

1、Event、Semaphore、Mutex是内核对象,能够跨进程使用,Critical Section不能跨进程,只能实现线程内互斥

2、 windows环境下,常用的实现进程同步有: 信号量(Semaphore) 事件(Event) 互斥锁(Mutex) 临界区(Critical Section):通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问; 虽然临界区同步速度很快,但却只能用来同步本进程内的线程,不能同步多个进程中的线程。 互斥锁(Mutex):为协调共同对一个共享资源的单独访问而设计的; 信号量:为控制一个具有有限数量用户资源而设计; 事件:用来通知线程有一些事件已经发生,从而启动后继任务的开始。

3、 A:临界区(只能实现线程同步) B:事件 C:互斥 D:信号量


4、以下关于多线程的叙述错误的是:

正确答案:C

A 线程同步的方法包括使用临界区,互斥量,信号量等

B 两个线程同时对简单类型全局变量进行写操作也需要互斥

C 实现可重入函数时,对自动变量也要用互斥量加以保护

D 可重入函数不可以调用不可重入函数


题解:

1、 在 实时系统的设计中,经常会出现多个任务调用同一个函数的情况。如果这个函数不幸被设计成为不可重入的函数的话,那么不同任务调用这个函数时可能修改其他任 务调用这个函数的数据,从而导致不可预料的后果。那么什么是可重入函数呢?所谓可重入是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会 出错。不可重入函数在实时系统设计中被视为不安全函数。 满足下列条件的函数多数是不可重入的: (1)函数体内使用了静态的数据结构; (2)函数体内调用了malloc()或者free()函数; (3)函数体内调用了标准I/O函数。 如何写出可重入的函数?在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用缺省态(auto)局部变量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号量来保护全局变量。或者调用该函数前关中断,调用后再开中断。 可重入函数可以被一个以上的任务调用,而不必担心数据被破坏。可重入函数任何时候都可以被中断,一段时间以后又可以运行,而相应的数据不会丢失。可重入函数或者只使用局部变量,即保存在CPU寄存器中或堆栈中;或者使用全局变量,则要对全局变量予以保护。

2、 A: 临界区不是方法。。 B: 单独是写操作不需要,如果写之前还有其他操作则可能要(毕竟还有原子操作),感觉这叙述很不严谨 C: 自动变量外部不可见,不需要互斥量保护 D: 可重入函数调用了不可重入函数那它就不是可重入函数了。。。 应该选AC吧。。


5、数据库以及线程发生死锁的主要原因是什么?

正确答案:ABC

A 资源分配不当

B 进程运行推进的顺序不合适

C 系统资源不足

D 进程过多


题解:

1、 死锁的规范定义如下:如果一个进程集合中的每个进程都在等待只能由该进程集合中其他进程才能引发的事件,那么该进程集合就是死锁的。 产生死锁的原因主要是: - 因为系统资源不足。 - 进程运行推进的顺序不合适。 - 资源分配不当等。 产生死锁的四个必要条件: 1. 互斥条件:每个资源要么已经分配给了一个进程,要么就是可用的。 2. 占有和等待条件:已经得到了某个资源的进程可以再请求新的资源。 3. 不可抢占条件:已经分配给一个进程的资源不能强制性地被抢占,只能被占有它的进程显式地释放; 4. 环路等待条件:死锁发生时,系统中一定有两个或者两个以上的进程组成的一条环路,该环路中的每个进程都在等待着下一个进程所占有的资源。 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。 四种处理死锁的策略: 1. 鸵鸟策略(忽略死锁); 2. 检测死锁并恢复; 3. 仔细对资源进行分配,动态地避免死锁; 4. 通过破坏引起死锁的四个必要条件之一,防止死锁的产生。 避免死锁的主要算法是基于一个安全状态的概念。在任何时刻,如果没有死锁发生,并且即使所有进程忽然请求对资源的最大请求,也仍然存在某种调度次序能够使得每一个进程运行完毕,则称该状态是安全的。从安全状态出发,系统能够保证所有进程都能完成,而从不安全状态出发,就没有这样的保证。 银行家算法:判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求,如果满足请求后系统仍然是安全的,就予以分配。不安全状态不一定引起死锁,因为客户不一定需要其最大贷款额度。

2、 ABC 产生死锁的原因主要是: (1) 因为系统资源不足。 (2) 进程运行推进的顺序不合适。 (3) 资源分配不当等。 产生死锁的四个必要条件: (1)互斥条件:一个资源每次只能被一个进程使用。 (2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 (3)不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 (4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 避免死锁: 死锁的预防是通过破坏产生条件来阻止死锁的产生,但这种方法破坏了系统的并行性和并发性。 死锁产生的前三个条件是死锁产生的必要条件,也就是说要产生死锁必须具备的条件,而不是存在这3个条件就一定产生死锁,那么只要在逻辑上回避了第四个条件就可以避免死锁。 避免死锁采用的是允许前三个条件存在,但通过合理的资源分配算法来确保永远不会形成环形等待的封闭进程链,从而避免死锁。该方法支持多个进程的并行执行,为了避免死锁,系统动态的确定是否分配一个资源给请求的进程。 预防死锁 :具体的做法是破坏产生死锁的四个必要条件之一


6、以下说法正确的是:

正确答案:ABCDE

A 在并行程度中,当两个并行的线程,在没有任何约束的情况下,访问一个共享变量或者共享对象的一个域,而且至少要有一个操作是写操作,就可能发生数据竞争错误。

B 原语Compare-and-swap(CAS)是实现无锁数据结构的通用原语。

C 获得内部锁的唯一途径是:进入这个内部锁保护的同步块或方法。

D volatile变量具有synchronized的可见性特性,但是不具备原子特性。

E 减小竞争发生可能性的有效方式是尽可能缩短把持锁的时间


题解:

1、A: 来自Thinking in java:如果你正在写一个变量,它可能接下在将被另一个线程读取,或者正在读取上一个已经被另一个线程写过的变量,那么你必须应用同步,并且,读写线程都必须用相同的监视器锁同步。–由此可以想到,如果多个线程都只读数据,则不会造成竞争错误,因为不会出现读脏数据或者数据不同步问题。 B. 无锁化编程常用方式之一 C. 当线程企图访问临界资源时,先会查看该临界资源当前是否已被加锁,如果没有被加锁,则对该临界资源加锁,并进入该同步块或方法,加锁后,其他线程也就无法访问该临界资源了。所以判定获取了一个内部锁的标准为:进入该同步区域 D. 保证可见性,调用volatile变量时,使用前都会刷新该变量,保证变量的值为最新的。不保证互斥性

2、所以不具备原子特性 E. 把持锁的时间短了,等待锁的时间也就短了,竞争可能性变小

3、 volatile的作用:1、修饰变量说明这个变量会意想不到地改变,优化器每次用到该变量,值都会重新从内存中读取它。2、进行多线程编程

4、 多任务环境下各任务间共享的标志应该加volatile.

5、 c答案应该错吧 是得先拿到锁才能进入临界区吧,怎么说成进临界区是拿到锁的唯一途径?


7、有三个线程T1,T2,T3,下面方法可以确保它们按顺序执行的有()该线程继续执行

正确答案:ABC

A 先启动最后一个(T3调用T2

BT2调用T1)

C 可以用线程类的join()方法在一个线程中启动另一个线程

D另一个线程完成

E 先启动第一个(T3调用T2

FT2调用T1)

G 以上选项说法都不正确


题解:

3、 BC答案正确,要想实现T1、T2、T3按照顺序执行,需要先执行T1,接着调用join()方法,实现执行完T1,就执行T2,同理实现执行完T2,执行T3线程。


8、操作系统死锁的必要条件(多选题):()

正确答案:AD

A 互斥条件

B 系统资源有限

C 进程调度不合理

D 环路等待条件


题解:

1、 死锁的原因主要是:(1) 因为系统资源不足。(2) 进程运行推进的顺序不合适。(3) 资源分配不当等。

产生死锁的四个必要条件:(1) 互斥条件(2) 请求与保持条件(3) 不剥夺条件。(4) 循环等待条件

2、 总结来说,别人问条件,你就找带条件二字的就好啦。。。。


9、两个线程并发执行以下代码,假设a是全局变量,初始为1,那么以下输出______是可能的? void foo(){

a=a+1;

printf("%d ",a);

}

正确答案:ABCD

A 3 2

B 2 3

C 3 3

D 2 2


题解:

1、3

2、2 2

3、3 和 3

4、3这3种情况都很好理解,我就不赘述了。 我来讲解一下为什么会输出2,2吧。 不知道朋友们有没有学过X86汇编,是这样的,你看a=a+1这一条语句,看起来是一条语句,实际上这条语句会被编译成大概3条指令的。 首先是先计算出a+1的值,那么就是: mov al

5、a (把a的值赋给寄存器al) add al

6、1 (寄存器al的值加1) 计算完a+1的值后,会再进行赋值,对应的指令是 : mov a

7、al(把寄存器al里的值赋给变量a) 大概就是这样的一个过程,3条指令。 你想既然这样,第1个进程可能是执行到 刚好计算完a+1的值,还没给变量a赋值(这时al里保存的是2,a依然是1),CPU就转换到执行第2个进程了,第2个进程完成这3条指令后,a的值为2,输出2,然后又回到第1个进程,这时开始执行mov a

8、al(把寄存器al里的值2赋给2),所以a的值为2,也输出2。 希望你们能看到我的观点,如果看不懂的话也没关系,简单地说就是:a=a+1这一句实际上执行是由很多条指令组成的。

9、 编译出来(一般来讲)大概会是这么几步: 读a +1 写a 再读a (这个可能被编译器优化掉) 写到屏幕上 两个线程,1和2: A 1读a 1+1 1写a // a =2 1再读a 2读a 2+1 2写a // a = 3 2再读a 2写到屏幕上 // 3_ 1写到屏幕上 // 2_ B 先执行所有1再执行所有2就得到B了,不解释了。 C 1读a 1+1 1写a // a = 2 2读a 2+1 2写a // a = 3 1再读a 2再读a … 就得到3_3_了,但如果没有再读a的步骤,就是_2_3或者_3_2了。 D 1读a 2读a 1+1 2+1 1写a // a = 2 2写a // a = 2 … 就得到2_2_了

:、 我怎么觉得都可能呢? 假设线程x和y同时执行,x和y可随时被抢占,a的初始值为1 A:3

;、 2 y先执行++a,a为2; y再执行printf,a入栈,在打印到终端之前切换到x x执行++a,a为3; x执行printf,输出3;再切换到y y执行打印,输出2 B:2 3 x先执行++a,a为2; x再执行printf,输出2;切换到y y执行++a,a为3; y执行printf,输出3; C:3 3 x先执行++a,a为2;切换到y y执行++a,a为3; y执行printf,输出3;切换到x x执行printf,输出3 D:2 2 类似C,a的初始值为0即可 这里关键有两点: (1)两个线程可随时被抢占 (2)++a和printf不是原子指令,可随时被打断;特别注意函数printf,a作为参数压栈后,a再变化则不会影响输出(printf实际打印的是压栈的参数,是值拷贝的栈变量)


10、实时操作系统的基本特性有?

正确答案:AB

A 提供高可靠性

B 提供及时响应性

C 提供多路性:即众多联机用户可以同时使用同一台计算机

D 提供独占性:各终端用户感觉到自己独占了计算机


题解:

1、 C和D是分时操作系统的特点

2、 提供及时响应和高可靠性是实时操作系统主要特点。实时操作系统有硬实时和软实时之分,硬实时要求在规定的时间内必须完成操作,这是在操作系统设计时保证的;软实时则只要按照任务的优先级,尽可能快地完成操作即可。


答案汇总:

1、正确答案:B

2、正确答案:C

3、正确答案:A

4、正确答案:C

5、正确答案:ABC

6、正确答案:ABCDE

7、正确答案:ABC

8、正确答案:AD

9、正确答案:ABCD

10、正确答案:AB


以上部分题解来自牛客评论区,感谢评论区大佬的解释。

相关文章
|
6月前
|
存储 Java
创建一个乘法练习题生成器 using Java
创建一个乘法练习题生成器 using Java
|
7月前
|
人工智能 Java
Java练习题-输出二维数组对角线元素和
Java练习题-输出二维数组对角线元素和
|
7月前
|
存储 Java 索引
Java练习题-获取数组元素最大值
Java练习题-获取数组元素最大值
Java练习题-获取数组元素最大值
|
7月前
|
Java
<Java SE> 数组详解大全(附带练习题).一维数组、二维数组、数组拷贝、数组遍历...
<Java SE> 数组详解大全(附带练习题).一维数组、二维数组、数组拷贝、数组遍历
57 0
|
7月前
|
Java 索引
Java练习题-用冒泡排序法实现数组排序
Java练习题-用冒泡排序法实现数组排序
|
7月前
|
Java
Java练习题-键盘录入字符串实现大小写转换
Java练习题-键盘录入字符串实现大小写转换
|
7月前
|
Java
Java练习题-输出斐波那契(Fibonacci)数列
Java练习题-输出斐波那契(Fibonacci)数列
|
7月前
|
算法 Java 程序员
Java数组全套深入探究——进阶知识阶段4、一维数组练习题
Java数组全套深入探究——进阶知识阶段4、一维数组练习题
64 0
Java数组全套深入探究——进阶知识阶段4、一维数组练习题
|
7月前
|
存储 Java
Java程序设计练习题8异常处理
Java程序设计练习题8异常处理
180 0
|
7月前
|
Java
java字符串练习题8、同构字符串
java字符串练习题8、同构字符串
56 0
java字符串练习题8、同构字符串