牛客刷题笔记--并发

1 下面关于并行和并发的区别,说法错误的是?(C)

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

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

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

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

答:

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

2 下列关于多线程,多进程,多任务的区别与关系描述正确的有?(ABC)

线程是指进程内的一条执行线路,或者说是进程中可执行代码的单独单元,它是操作系统的基本调度单元。

一个进程至少有一个线程,即主线程,也可以有多个线程协同工作。

进程从主线程开始执行,进而可以创建一个或多个附加线程来执行该进程内的并发任务,这就是基于线程的多任务。

上述描述都是错误的


操作系统中,申请资源的基本单位是进程,在CPU得到执行的基本单位是线程。进程由程序段,数据段,PCB组成

3 数据库以及线程发生死锁的必要条件是什么?(ABCD)

互斥条件:一个资源每次只能被一个进程使用

请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

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

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

先启动最后一个(T3调用T2,T2调用T1)

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

先启动第一个(T3调用T2,T2调用T1)

以上选项说法都不正确

5 两个线程并发执行以下代码,假设a是全局变量,初始为1,那么以下输出__ABCD____是可能的?

3 2

2 3

3 3

2 2

牛客刷题笔记--并发_第1张图片

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

并发,并发

并发,并行

并行,并行

并行,并发

并发是同时处理很多事情,
并行是同时执行很多事情;
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。

7 多个线程可同时操作一个数据,为了保证该数据的准确性,可将操作该数据的部分改为:D

只写

只读

异步

同步

答案:D
对该数据加锁,放在同步代码块
synchronize(){
}

  1. 并发:在 操作系统 中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个 处理机 上运行。其中两种并发关系分别是同步和互斥

  2. 互斥:进程间相互排斥的使用临界资源的现象,就叫互斥。

  3. 同步: 进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。
    其中并发又有伪并发和真并发,伪并发是指单核处理器的并发,真并发是指多核处理器的并发。

  4. 并行:在单处理器中多道程序设计系统中,进程被交替执行,表现出一种并发的外部特种;在多处理器系统中,进程不仅可以交替执行,而且可以重叠执行。在多处理器上的程序才可实现并行处理。从而可知,并行是针对多处理器而言的。并行是同时发生的多个并发事件,具有并发的含义,但并发不一定并行,也亦是说并发事件之间不一定要同一时刻发生。

  5. 多线程:多线程是程序设计的逻辑层概念,它是进程中并发运行的一段代码。多线程可以实现线程间的切换执行。

  6. 异步:异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。线程就是实现异步的一个方式。异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。
    异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。实现异步可以采用多线程技术或则交给另外的进程来处理。

8 以下关于多线程的叙述错误的是: c

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

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

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

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

牛客刷题笔记--并发_第2张图片

可重入函数可认为是可以被中断的函数,自动变量定义的时候才被创建,函数返回时,系统回收空间,他是局部作用域变量,不需要互斥量。可重入函数对全局变量才需要互斥量保护。

9 有两个线程,最初 n=0,一个线程执行 n++; n++; 另一个执行 n+=2; 问,最后可能的 n 值? BCD

1

2

3

4

大家要知道 C语言中的 ++ 和 += 并不是原子操作,而是通过多条微程序组成的,因此 ++ 和 += 在执行过程中可能被中断的
第一种可能情况:现在假设两个线程没有并行顺序执行的那么结果显然是 4。
第二种可能情况:再假设现在第一个n++ 已经执行完了 但是结果还没有写回内存 这个时候 n+=2 已经全部执行完 2 写进了内存 结束 然后回到n++的写回操作 这个时候内存就从2被改回1了,后面再来一次n++ 结果就为2。
第三种可能情况: 第n+=2 先读取n的值到寄存器 即0入寄存器 这个时候被中断 第一个n++开始执行 并直到结束 内存被改成了1 ,然后 n+=2 继续执行 结束后内存变为2 第二个n++再执行 结果就是3了

牛客刷题笔记--并发_第3张图片
10 产生系统死锁的原因是由于(C)

进程释放资源

一个进程进入死循环

多个进程竞争,资源出现循环等待

多个进程竞争共享型设备

存在竞争资源环图的时候会发生死锁,因为都不想释放已经拥有的资源但是还要去竞争别人不想释放的资源,那么问题就来了。大家都等呗,那就一起死锁吧。
可以通过对资源编号有序申请、一次性全部申请才能运行否则全部放弃和预分配避免进入死锁等方式避免死锁。

产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之
一不满足,就不会发生死锁

D选项:共享型设备是指在一段时间内允许多个进程同时访问的设备

11 假设有4条语句s1:a=5x;s2:b=5+y;s3:c=a+b;s4:d=c+y;根据bernstein条件,下面说法正确的是?D

s1,s4可并发执行

s1,s2不可并发执行

s2,s3可并发执行

s3,s4不可并发执行

Bernstein条件是指两个过程如果有数据冲突,那么就没法并行执行。
A选项中,s4需要读数据c,而s3中数据c依赖于a,因此s4依赖于s1的结果,s1、s4不可并发执行。
B选项中,s1依赖于x,s2依赖于y,s1和s2之间没有数据冲突,可以并发执行。
C选项中,s3依赖于b,s3和s2之间有数据冲突,不可并发执行。
D选项中,s4需要数据c,s4的执行依赖s3的结果,不可并发执行。

12 轮询任务调度与抢占式任务调度的区别?BD

抢占式调度优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度

轮询调度优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度

轮询调度实现相对较复杂

抢占式调度实现相对较复杂

轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环。
抢占式任务调度允许调度程序根据某种原则去暂停某个正在执行的进程,将已分配给该进程的处理机重新分配给另一进程。抢占方式的优点是,可以防止一个长进程长时间占用处理机,能为大多数进程提供更公平的服务,特别是能满足对响应时间有着较严格要求的实时任务的需求。
因为抢占式调度可能会暂停一些进程,需要记录进程的运行状态,较为复杂。轮询式只需要轮流分配资源,调度简单

13 无锁化编程有哪些常见方法?ABCD

针对计数器,可以使用原子加

只有一个生产者和一个消费者,那么就可以做到免锁访问环形缓冲区(Ring Buffer)

RCU(Read-Copy-Update),新旧副本切换机制,对于旧副本可以采用延迟释放的做法

CAS(Compare-and-Swap),如无锁栈,无锁队列等待

A 原子操作是汇编级别支持的指令lock xadd,如c++中的interlockIncrement,java中有AutomicInteger都是对其的封装。简单变量的线程同步用这种方式效率最高。
B 多个生产者和多个消费者,一样可以做到免锁访问,但要使用原子操作。这里的意思应该是不用原子操作级别的免锁,理由也很简单,生产者和消费者需要修改的位置是分开的(生产者加在尾部,消费者从头部消费),且只有一个读一个写,不会发生冲突。所以只有一点需要关注,就是尾部指针和头部指针每次需要比较以避免生产溢出或者过度消费,而简单变量的读操作都是原子的。
C 类似的一个概念叫CopyOnWrite,复制一份,修改完后,替换回去时只需替换一个指针或引用,锁住的粒度非常小。但有可能还有线程持有的是旧的指针,因此旧的副本需要延迟释放。
D 汇编级别支持的指令cmpxchg,锁定内存地址,比较地址中修改前的内容是否与修改时的值一致,如果不一致就说明有其他线程改动,需要重新做。如,内存地址0x123456中原来存放的是10101010,但CPU执行到cmpxchg指令时,发现内存中变成了11111111,那么就认为其他线程已经修改了这个地址的值,需要重新读取0x123456中的值11111111,再做一次cmpxchg,如果这次发现内存中仍然是11111111,那么cmpxchg就会把新的值写入到0x123456中去。这里面有个ABA问题,就是有线程改了2次从11111111 -> 10111111 -> 11111111,那么CAS操作是识别不了的,需要从业务层去避免,如果直接在0x123456再放一个地址值,而地址值如果不先释放再重新申请内存,就不会出现重复值。

JAVA对应:
A:AtomicInteger
B:http://ifeve.com/the-disruptor-lock-free-publishing/
C:CopyOnWriteArrayList
D:Unsafe

14 关于进程和线程,下面说法正确的是 BCD

线程是资源分配和拥有的单位

线程和进程都可并发执行

在linux系统中,线程是处理器调度的基本单位

线程的粒度小于进程,通常多线程比多进程并发性更高

不同的线程共享相同的栈空间

A 错误,进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
B 正确,二者均可并发执行。
C 正确,线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
D 正确, 线程的划分尺度小于进程,使得多线程程序的并发性高
E错在:即便是同一进程里的多个线程,每个线程也有自己独立的栈空间,其他资源是共享的。

15 一个全局变量tally,两个线程并发执行(代码段都是ThreadProc),问两个线程都结束后,tally取值范围为_______A

int tally=0;//全局变量
  void ThreadProc(){
     for(int i=1;i<=50;i++)
  tally+=1;
}

[50,100]

[100.100]

[1275,2550]

[2550,2550]

最小值的情况:(线程a,b交替读取tally值)
a线程对tally加1后,还没有更新tally在内存中的值,线程b读取tally值,执行加1,更新tally为1,然后a线程重新读取tally值,这样交替运行,最终为50
最大值的情况:
a线程对tally加到50后,更新tally在内存中的值为50,然后线程b读取tally值,再执行加50运算,结果为100;

16 有关多线程,多进程的描述错误的是 D

子进程获得父进程的数据空间,堆和栈的复制品

线程可以与同进程的其他线程共享数据,但是它拥有自己的栈空间且拥有独立的执行序列

线程执行开销小,但是不利于资源管理和保护

进程适合在SMP机器上进行,而线程则可以跨机器迁移

SMP:Symmetrical Multi-Processing,对称性多核处理器,多进程可以在不同的核上运行,但是线程不可以跨机器迁移,因为线程是存在于单一的进程之中,只能在一个核上运行

牛客刷题笔记--并发_第4张图片
17 设在内存中有P1,P2,P3三道程序,并按照P1,P2,P3的优先级次序运行,其中内部计算和IO操作时间由下表给出(CPU计算和IO资源都只能同时由一个程序占用):
P1:计算60ms—》IO 80ms—》计算20ms
P2:计算120ms—》IO 40ms—》计算40ms
P3:计算40ms—》IO 80ms—》计算40ms
并行完成三道程序比单道运行节省的时间是(C)

80ms

120ms

160ms

200ms

这里节约的时间是在一个进程进行cpu操作的时候另一个进程可以进行io操作,反之也是可以的。但是要注意的是,高优先级的进程可以剥夺资源并直至完成才让出资源。 本题,在p1进行io80ms期间,p2可占用cpu80ms,之后被迫让出给p1执行cpu20ms后继续完成还剩的cpu40ms。按照这种思路,共可以节约80+40+40=160ms. 选C ;

18 Inter-process communication (IPC) is the transfer of data among processes. Which of the following is NOT a typical programming technique for IPC?

mutex

pipe

socket

message queue

题目问哪一个不是进程间通信的方式。其中进程间通信的方式有管道(pipe)、共享存储器系统、消息传递系统(message queue)以及信号量。而mutex是互斥锁,在锁机制中通过原语保证资源状态的检查和修改作为一个整体来执 行,以保证共享数据操作的完整性,并不能在两个进程间传递消息。网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket,也就是说socket也是两个进程间的通信方式。

19 竞选条件(race condition)的情况下,两线程执行如下代码段,其中count为共享变量,线程1执行代码段A,线程2指向代码段B,那么变量count的值可能为 ABC
int count = 10;

代码段A:
Thread_1()
{
    //do something
    count++;
}
代码段B:
Thread_2()
{
    //do something
    count--;
}

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

Critical Section

Event

Mutex

Semaphore

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

牛客刷题笔记--并发_第5张图片
21 一个容器类数据结构,读写平均,使用锁机制保证线程安全。如果要综合提高该数据结构的访问性能,最好的办法是______。C

只对写操作加锁,不对读操作加锁

读操作不加锁,采用copyOnWrite的方式实现写操作

分区段加锁

无法做到

A,只对写操作加锁,不对读操作加锁,会造成读到脏数据
B,CopyOnWrite的核心思想是利用高并发往往是读多写少的特性,对读操作不加锁,对写操作,先复制一份新的集合,在新的集合上面修改,然后将新集合赋值给旧的引用。这里读写平均,不适用
C,分段加锁,只在影响读写的地方加锁,锁可以用读写锁,可以提高效率
脏数据:从目标中取出的数据已经过期、错误或者没有意义,这种数据就叫做脏数据。 脏读:读取出来脏数据就叫脏读。

22 数据库以及线程发生死锁的原理是什么? ABC

资源分配不当

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

系统资源不足

进程过多

产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
产生死锁的四个必要条件:
(1)互斥条件:一个资源每次只能被一个进程使用。
(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3)不可剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁:
死锁的预防是通过破坏产生条件来阻止死锁的产生,但这种方法破坏了系统的并行性和并发性。
死锁产生的前三个条件是死锁产生的必要条件,也就是说要产生死锁必须具备的条件,而不是存在这3个条件就一定产生死锁,那么只要在逻辑上回避了第四个条件就可以避免死锁。
避免死锁采用的是允许前三个条件存在,但通过合理的资源分配算法来确保永远不会形成环形等待的封闭进程链,从而避免死锁。该方法支持多个进程的并行执行,为了避免死锁,系统动态的确定是否分配一个资源给请求的进程。
预防死锁:具体的做法是破坏产生死锁的四个必要条件之一。

银行家算法:该算法需要检查申请者对各类资源的最大需求量,如果现存的各类资源可以满足当前它对各类资源的最大需求量时,就满足当前的申请。换言之,仅当申请者可以在一定时间内无条件归还它所申请的全部资源时,才能把资源分配给它。这种算法的主要问题是,要求每个进程必须先知道资源的最大需求量,而且在系统的运行过程中,考察每个进程对各类资源的申请需花费较多的时间。另外,这一算法本身也有些保守,因为它总是考虑最坏可能的情况。

23 实时操作系统的基本特性有? AB

提供高可靠性

提供及时响应性

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

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

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

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

互斥条件

系统资源有限

进程调度不合理

环路等待条件

产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

死锁的原因主要是:(1) 因为系统资源不足。(2) 进程运行推进的顺序不合适。(3) 资源分配不当等。
产生死锁的四个必要条件:(1) 互斥条件(2) 请求与保持条件(3) 不剥夺条件。(4) 循环等待条件

25 下列哪种操作可能带来死锁? C

lock(m1) lock(m2) unlock(m1) unlock(m2)

lock(m1) lock(m2) unlock(m2) lock(m2) unlock(m1) unlock(m2)

lock(m1) lock(m2) unlock(m1) lock(m1) unlock(m2) unlock(m1)

lock(m1) lock(m2) unlock(m1) unlock(m2) lock(m1) unlock(m1)

假设有两个线程,线程1执行到lock(m1),lock(m2),unlock(m1),此时线程1持有锁m2,想要获取锁m1;线程2执行到lock(m1),此时线程2持有锁m1,想要获取锁m2。两个线程都拿着对方想要得到的锁,造成死锁。

26 假设如下代码中,若t1线程在t2线程启动之前已经完成启动。代码的输出是(B)

public static void main(String[]args)throws Exception {
    final Object obj = new Object();
    Thread t1 = new Thread() {
        public void run() {
            synchronized (obj) {
                try {
                    obj.wait();
                    System.out.println("Thread 1 wake up.");
                } catch (InterruptedException e) {
                }
            }
        }
    };
    t1.start();
    Thread.sleep(1000);//We assume thread 1 must start up within 1 sec.
    Thread t2 = new Thread() {
        public void run() {
            synchronized (obj) {
                obj.notifyAll();
                System.out.println("Thread 2 sent notify.");
            }
        }
    };
    t2.start();
}

Thread 1 wake up
Thread 2 sent notify.

Thread 2 sent notify.
Thread 1 wake up

A、B皆有可能

程序无输出卡死

选择B
执行obj.wait();时已释放了锁,所以t2可以再次获得锁,然后发消息通知t1执行,但这时t2还没有释放锁,所以肯定是执行t2,然后释放锁,之后t1才有机会执行。

notify()就是对对象锁的唤醒操作。但有一点需要注意的是notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作

线程间协作:wait、notify、notifyAll

在 Java 中,可以通过配合调用 Object 对象的 wait() 方法和 notify()方法或 notifyAll() 方法来实现线程间的通信。在线程中调用 wait() 方法,将阻塞等待其他线程的通知(其他线程调用 notify() 方法或 notifyAll() 方法),在线程中调用 notify() 方法或 notifyAll() 方法,将通知其他线程从 wait() 方法处返回。

Object 是所有类的超类,它有 5 个方法组成了等待/通知机制的核心:notify()、notifyAll()、wait()、wait(long)和 wait(long,int)。在 Java 中,所有的类都从 Object 继承而来,因此,所有的类都拥有这些共有方法可供使用。而且,由于他们都被声明为 final,因此在子类中不能覆写任何一个方法。

这里详细说明一下各个方法在使用中需要注意的几点。
wait()

public final void wait() throws InterruptedException,IllegalMonitorStateException

该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止。在调用 wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用 wait()方法。进入 wait()方法后,当前线程释放锁。在从 wait()返回前,线程与其他线程竞争重新获得锁。如果调用 wait()时,没有持有适当的锁,则抛出 IllegalMonitorStateException,它是 RuntimeException 的一个子类,因此,不需要 try-catch 结构。
notify()

public final native void notify() throws IllegalMonitorStateException

该方法也要在同步方法或同步块中调用,即在调用前,线程也必须要获得该对象的对象级别锁,的如果调用 notify()时没有持有适当的锁,也会抛出 IllegalMonitorStateException。

该方法用来通知那些可能等待该对象的对象锁的其他线程。如果有多个线程等待,则线程规划器任意挑选出其中一个 wait()状态的线程来发出通知,并使它等待获取该对象的对象锁(notify 后,当前线程不会马上释放该对象锁,wait 所在的线程并不能马上获取该对象锁,要等到程序退出 synchronized 代码块后,当前线程才会释放锁,wait所在的线程也才可以获取该对象锁),但不惊动其他同样在等待被该对象notify的线程们。当第一个获得了该对象锁的 wait 线程运行完毕以后,它会释放掉该对象锁,此时如果该对象没有再次使用 notify 语句,则即便该对象已经空闲,其他 wait 状态等待的线程由于没有得到该对象的通知,会继续阻塞在 wait 状态,直到这个对象发出一个 notify 或 notifyAll。这里需要注意:它们等待的是被 notify 或 notifyAll,而不是锁。这与下面的 notifyAll()方法执行后的情况不同。
notifyAll()

public final native void notifyAll() throws IllegalMonitorStateException

该方法与 notify ()方法的工作方式相同,重要的一点差异是:

notifyAll 使所有原来在该对象上 wait 的线程统统退出 wait 的状态(即全部被唤醒,不再等待 notify 或 notifyAll,但由于此时还没有获取到该对象锁,因此还不能继续往下执行),变成等待获取该对象上的锁,一旦该对象锁被释放(notifyAll 线程退出调用了 notifyAll 的 synchronized 代码块的时候),他们就会去竞争。如果其中一个线程获得了该对象锁,它就会继续往下执行,在它退出 synchronized 代码块,释放锁后,其他的已经被唤醒的线程将会继续竞争获取该锁,一直进行下去,直到所有被唤醒的线程都执行完毕。
深入理解

如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。

当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。

优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

26 java中Hashtable, Vector, TreeSet, LinkedList哪些线程是安全的?AB

Hashtable

Vector

TreeSet

LinkedList

线程安全概念
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的

线程安全问题都是由全局变量及静态变量引起的

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
牛客刷题笔记--并发_第6张图片

LinkedList 和 ArrayList 都是不同步的,线程不安全;
Vector 和 Stack 都是同步的,线程安全;
Set是线程不安全的;

Hashtable的方法是同步的,线程安全;
HashMap的方法不是同步的,线程不安全;

27 以下说法正确的是: ABCDE

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

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

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

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

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

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

你可能感兴趣的:(多线程)