栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVA-并发

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVA-并发

JAVA并发 1.为什么使用并发,什么是并发

●可以提升多核CPU的利用率:一般来说一个主机会有多个CPU核心,我们可以创建多个线程,将不同的线程交给不同的核心去执行,这样就可以提升CPU的使用率。

●方便进行业务拆分,提升应用性能

●比如我们常见的数据库连接池,就是多线程的应用

●缺陷:

​ ■线程也是程序需要占用内存,线程越多,消耗内存越多

​ ■多线程需要协调管理(上下文切换),还会浪费一部分CPU性能

​ ■线程之间对共享资源的访问会相互影响,会造成线程不安全现象。

2.并发编程的三个要素

●原子性:不可再分,要么不做,要么全做,(JAVA通过synchronized或锁来解决)

●可见性:一个线程对共享变量的修改,另一个线程能立刻看到(我觉得是通过Voliate关键字解决的)

●有序性:程序执行的顺序按照代码的先后顺序执行(处理器可能会对指令重排序,通过Happens-Before规则解决)

3.并发和并行有什么区别

●并发:多个任务在同一个核上,按细分的时间片轮流执行,由于切换很快,所以看起来像是同时执行。

●并行:单位时间内,多个处理器或多核处理器同时处理多个任务,是真正意义上的同时进行。

●串行:有n个任务,由一个线程按顺序执行。

4.进程线程和协程

●进程:一个内存中运行的应用程序,每个在运行的程序都是一个进程,是操作系统资源分配的基本单位,每个进程都有独立的代码和数据空间(程序上下文),程序切换会有较大开销。

●线程:进程中的一个任务,在程序中独立运行,是处理器任务调度和执行的基本单位,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,切换开销较小。

●协程:由于线程切换涉及到上下文切换,导致状态的切换都非常消耗性能,所以出现了一种比线程更加轻量级的存在,一个进程可以有多个协程,区别是协程不是被OS内核管理而是由程序控制(在用户态,所以不像线程切换那样消耗资源)

​ ■Java没有实现,Python通过关键字yield实现了(Java的yield方法是让线程回到就绪队列)。下面程序中创建了一个consumer的协程,在协程中消费数据,当协程运行到yield关键字的时候,会暂停于那行,等主线程用send方法发送了数据,协程才会接收到数据,继续执行(所以是由程序控制)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BULYyVtL-1650425957586)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/119.png)]

●一个进程至少有一个线程,可以有多个线程,线程之间共享很多数据(详细见JVM)

●一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃后,可能导致整个进程都死掉

●每个进程有独立的程序运行出入口,但是线程不能独立执行,必须依存于应用程序中。

5.什么是上下文切换

●多线程编程中一般线程数多于CPU核心数,而一个核心同一时刻只能被一个线程使用,所以就按时间片轮转,当一个线程时间片用完就会先保存自己状态,然后切换到另一个任务,这个过程就是上下文切换。

●Linux与其他操作系统下那个比有个优点就是上下文切换和模式切换的时间消耗少。

6.守护线程和用户线程的区别

●用户线程(User):运行在前台,执行具体的任务。eg:程序主线程

●守护线程(Daemon):运行在后台,为其他前台线程服务,一旦用户线程结束,守护线程随着JVM一起结束。eg:GC

7.线程死锁

●线程死锁是指两个或两个以上的进程(线程),在竞争公共资源的过程中行程单一种阻塞现象,如无外力作用,将无法推进下去。

●形成死锁的必要条件:

​ ■互斥:同一资源在某一时间段内只能被一个进程占用。

​ ■不可剥夺:别人拥有的资源,不能剥夺下来

​ ■循环等待:若干进程相互等待对方释放资源

​ ■保持等待:进程有一定的资源,但不够运行,也不会主动放弃资源,一直在等待。

●避免死锁:使用定时锁,lock,tryLock来代替内部锁机制。

8.JAVA中常见的锁

●同步锁:同一时刻,一个同步锁只能被一个线程访问,以对象为依据,在Java中任何对象都可以做为锁,通过synchronized关键字进行同步,实现对竞争资源的互斥访问。

●独占锁(可重入的互斥锁):在同一个时间点,只能被一个线程持有;可重入,即可被单个线程多次获取,根据锁的获取机制又可分为公平锁和非公平锁,Java中通过ReentrantLock实现独占锁,默认为非公平锁。

​ ■公平锁:按照自旋时间即先来先得的规则,线程依次排队,公平获取锁。Java中,ReetrantLock中有一个Sync类型的成员变量sync,它的实例为FairSync类型的时候,ReetrantLock为公平锁。设置sync为FairSync类型,只需要Lock lock = new ReetrantLock(true)

​ ■非公平锁:当线程要获取锁的时候,会无视自旋时间等待队列而直接获取锁,如果获取不到再进入等待队列,ReetrantLock默认为非公平锁,或Lock lock = new ReetrantLock(false)

●共享锁:我们常说的读锁就是共享锁,可以被多个线程获取,而写锁就是独占锁,只能被一个线程获取。

●Java中,读写锁为ReadWriteLock接口定义,实现类是ReentrantReadWriteLock,包括内部类ReadLock和WriteLock。方法readLock(),和writeLock()分别返回读操作的锁和写操作的锁。

9.创建线程的方式

●继承Thread类:继承Thread类,重写run方法即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lRhYJsKC-1650425957587)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/120.png)]

●实现Runnable接口:实现run方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6shOW5om-1650425957588)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/121.png)]

●实现Callable接口:重写call方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V2CrnhAv-1650425957588)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/122.png)]

●Runnable和Callable的区别

​ ■Runnable接口run方法无返回值,Callable接口call方法有返回值,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。

​ ■Runnable接口run方法只能抛出运行时异常,并且无法捕获处理;Callable接口call方法允许抛出异常,可以获取异常信息。

●线程的run和start方法区别

​ ■Start方法用于启动线程,真正实现了多线程;run方法用于执行线程的运行代码,run可以重复调用,而start只能调用一次(每个Thread子类对象都有一个状态status,表示是否执行过,禁止执行两次同一个线程)

​ ■调用start后,线程会被放到就绪队列,并不是立即执行,而是通过JVM,轮到该线程后(时间片到了),Thread会调用run方法,执行本线程的线程体(start相当于执行线程的准备工作,然后自动执行run)

​ ■run方法只是本线程中的一个函数而已,如果直接调用run方法,相当于调用了一个普通函数而已,直接调用run方法必须等待前面run方法执行完毕才能执行,所以根本就不是多线程。所以不要直接调用run方法。

10.Future和FutureTask

●Future是JDK1.5引入的一个接口,用来获取异步结果

●Future代表的是异步执行的结果,当异步执行之后,返回的结果会保存在future中。

●那么何时使用呢?1:计算密集型场景;2:处理大量数据;3:远程方法调用,在xhs中下面就是调用其他远程服务来获取结果,创建了四个Future,这样的话,假设四个任务分别耗时200,200,200,300,那么一共耗时为300。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qc00JWwU-1650425957588)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/134.png)]

●在需要使用这个的时候,创建一个ExecutorService对象(项目中采用bean注入一个就行),重写对象的submit方法,接受一个Callable参数(所以需要实现call方法),并返回一个Future(一般使用Lambda表达式简化流程)

●Future对象的isDone方法可以判断这个异步操作是否执行完毕

●如果执行完毕的话,可以通过这个对象的get方法来获取最终的结果

●FutureTask接口:表示一个异步的运算任务。FutureTask里面可以传入一个Callable的具体实现类,可以对这个异步运算的任务的结果进行等待获取、判断是否完成、取消任务等操作。

11.线程的状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-StTu48dk-1650425957589)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/123.png)]

●新建(new):新建一个线程对象(并未启动)

●就绪(Runnable):创建线程后,调用start方法,将对象放入就绪队列中

●运行态(Running):就绪态对象获得了CPU时间片,执行程序代码(就绪态是运行态的唯一入口)

●阻塞(Block):处于运行态的线程由于某种原因,暂时放弃CPU的使用权,阻塞分为以下几种情况:

​ ■等待阻塞:运行状态中的线程执行wait()方法,JVM会把该线程放入等待队列,使本线程进入阻塞等待状态,会释放锁,即醒过来之后,要去重新申请锁。

​ ■同步阻塞:线程在获取synchronized同步锁失败(可能被其他线程占用),则JVM会把该线程放入锁池中,线程会进入同步阻塞状态,其他线程完成后,会将其唤醒。

​ ■其他阻塞:通过调用线程的sleep()或join()或发出IO请求时,线程会进入阻塞状态。当sleep状态超时,join()等待线程终止或超时,或IO处理完毕后,线程进入就绪状态。

●死亡(dead):线程run()、main()方法结束,或者因为异常退出了run方法,则该线程结束生命周期,死亡的不可在此复生。

12.Java中用到的线程调度算法(就绪>运行)

●分时调度模型:所有的线程根据时间片轮流获得CPU使用权

●抢占式调度模型:优先让就绪池中优先级高的线程占用CPU,如果都一样,则随机选一个,如果发生了以下情况,就终止线程的运行。

​ ■线程体调用了yield方法,主动让出CPU的占有权

​ ■线程体调用sleep方法,使线程进入睡眠

​ ■线程由于IO进入阻塞

​ ■另一个更高级的线程出现

​ ■时间片用完

13.与线程同步及调度相关的方法

●wait():是一个线程进入阻塞态,并释放其拥有的锁,应该在循环内使用,当线程获取到CPU开始执行,其他条件可能还没有满足,所以在处理前,循环检测条件是否满足会更好。

●sleep():使一个正在运行的线程进入睡眠状态,是一个静态方法。

●notify():唤醒一个处于等待状态的线程,但是不确定唤醒的到底是哪个线程(异步性)

●notifyAll():唤醒所有处于等待状态的线程,注意唤醒后的线程还需要自己去抢锁,来决定是否能真正执行。

●yield():当前线程从运行态变为就绪态,是一个静态方法。

●sleep与wait的区别:

​ ■sleep是线程类的静态方法,而wait是Object类的方法

​ ■sleep不释放锁,而wait释放锁

​ ■wait用于线程间通信,而sleep用于暂停

​ ■wait调用后不会自动苏醒,需要别的线程调用同一对象上的notify或者notifyAll;而sleep方法执行后会自动苏醒

●为什么 wait notify notifyAll 都定义在Object类里:因为Java想让所有对象都可以作为锁,这些方法用于释放锁,唤醒线程,并且Java的线程中并没有可供任何对象使用的锁,所以任意对象调用方法一定在Object类内。

14.Java线程之间如何通信及同步

●通信指线程之间如何交换信息,Java线程是通过共享内存模型的方式进行的

●共享内存模型即Java内存模型JMM,其决定一个线程对共享变量的写入对另一个线程可见,线程之间共享变量存在主内存中,每个线程都有一个私有的本地内存,其通信步骤如下:

​ ■A把本地内存A中更新过的共享变量刷新到主内存中

​ ■B到主内存读取A更新过的共享变量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eXnc27br-1650425957590)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/125.png)]

​ ■这个方法其实就是通过volatile关键字,使变量保证可见性,然后通过共享内存思想实现通信。

​ ■还可以通过锁,sychronized以及wait notify实现

15.重排序

●程序一般按照代码先后顺序执行,处理器为了提高程序的运行效率,会对输入代码进行优化(JVM部分也会详述),进行重排序

,并不保证各个语句执行先后顺序与原来一致,但是保证执行结果与源代码一致。

●重排序对单线程运行不会产生影响,但是对多线程可能会造成影响。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8eCGE74H-1650425957590)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/126.png)]

●重排序需要遵守的规则:as -if-serial:

​ ■不管怎么排序,结果不会改变

​ ■不存在数据依赖的可以被编译器和处理器重排序

​ ■一个操作依赖两个操作,如果这两个操作不存在依赖,可以重排序

​ ■单线程这个规则不会有问题,但多线程可能有问题

●多线程重排序必须遵守的规则:happens -before

​ ■必须保证同步的多线程程序执行结果不被改变

16.关键字Synchronized

●用来实现控制线程同步的,可以修饰类、方法、变量

●早起的synchronized属于重量级锁,效率低下,因为监视器monitor是依赖底层操作系统Mutex Lock实现的,而Java线程是映射到OS的原生线程上的。如果要挂起或唤醒一个线程,都需要OS帮忙,而操作系统实现线程间的切换需要从用户态切换到内核态,这个过程消耗巨大的资源,JDK6之后进行了优化。

●项目中何时使用:

​ ■修饰实例方法:作用于当前对象实例加锁,进入同步代码前要获得当前对象的实例锁。(一个线程进入一个对象的synchronized后,就会获得这个对象的锁,别的线程只能进入这个对象的非synchronized方法了)

​ ■修饰类/静态方法:给当前类加锁,会作用于类的所有对象实例(注:线程A调用实例A的synchronized费静待方法,线程B调用这个实例所属类的静态synchronized不会互斥,因为是两个锁)

​ ■修饰代码块:指定加锁对象,对给定对象加锁,进入同步代码块钱要获得给定对象的锁。

●底层原理:通过一个monitor(监视器锁)的对象来完成的,每个对象都有一个monitor,每个synchronized修饰过的代码,当他的monitor被占用时就会处于锁定状态并且尝试获取monitor的所有权。

​ ■如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程为monitor的所有者。

​ ■如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数+1(可重入的原理)。

​ ■如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再尝试获取monitor的所有权。

●自旋:很多synchronized里面都是很简单的代码,执行非常快,这样的话让其阻塞就很不合适(因为阻塞涉及到用户态和内核态切换的问题,而且很耗费性能),所以就让其在synchronized边界做忙循环(不放弃CPU,一直做空循环),这就是自旋。

●锁升级原理:每个对象的对象头都有一个threadid字段,第一次访问到 时候threadid为空,JVM让其斥候偏向锁,并且threadid设置为线程ID,再次进入的时候会判断threadid是否与线程ID一致,如果一致可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋一定次数来等待这个锁,如果自旋一定次数后,还没有得到这个锁,此时就会把锁升级为重量级锁。

​ ■偏向锁:如果运行过程中,同步锁只有一个线程访问,则线程不需要重新同步,可以减少加锁/解锁的一些CAS操作

​ ■轻量级锁:偏向锁升级而来,有其他进程过来访问了

​ ■重量级锁:JVM中最基础的锁,这个状态下,JVM会阻塞加锁失败的线程,并且在目标锁释放的时候,唤醒线程。

17.关键字volatile

●Java提供volatile关键字来保证可见性和指令重排,volatile提供happens-before的保证,确保一个线程的修改对其他线程可见。当一个共享变量被volatile修饰时,他会保证修改的值会被立即更新到主内存中,当其他线程读取他时,会去内部才能读新值。

●与synchronized的区别:

​ ■synchronized表示只有一个线程可以获取作用于对象的锁,执行代码,阻塞其他线程。

​ ■volatile表示变量在CPU的寄存器是不确定的,必须从主存中读取,保存多线程环境下变量的可见性,禁止指令重排序。

​ ■volatile是变量修饰符,而synchronized可以修饰方法、类、变量。

​ ■volatile仅仅实现变量的修改可见性,不保证原子性,而synchronized既可以保证修改可见性,又可以保证原子性。

​ ■volatile不会造成线程的阻塞,synchronized会造成线程阻塞。

18.悲观锁和乐观锁

●悲观锁:总是假设最坏,即每次去拿数据的时候都认为别人会修改,所以每次拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞。synchronized其实就是悲观锁

●乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是更新的时候会判断一下在此期间有没有人去更新这个数据,可以采取版本号机制解决ABA问题。

19.CAS(compare and swap,比较交换)

●一种基于锁的操作,而且是乐观锁

●CAS操作包含三个数:内存位置(V),预期原值(A),新值(B)。如果内存地址里的值和A相同,就将内存中的值改为B。CAS是通过无限循环来获取数据的,如果在第一轮循环中,a线程地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能执行。●CAS产生的问题:

​ ■ABA问题:一个线程one从V取出A,这时候另一个线程two也从V取出了A,并且进行了一些操作变为了B,然后two又将V位置的数据变为了A,这时候one进行CAS操作发现内存中仍然是A,并且one操作成功,这时候虽然成功,但可能存在潜在的问题(中间加了很多操作,可以通过版本号机制解决)

​ ■循环时间长开销大:对于线程冲突严重的情况,CAS自旋的几率很大,浪费更多的CPU资源,效率不如synchronized

​ ■只能同时保证一个共享变量的原子操作。

20.原子类(java.util.concurrent.atomic)

●相当于一种泛化的volatile变量,支持原子的和有条件的读写改操作

●eg:AutomicInteger表示一个int类型的值,并提供了get和set方法

●常见原子类

​ ■AutomicBoolean

​ ■AutomicInteger

​ ■AutomicLong

​ ■AutomicReference

●Automic原理:automic包中的类在多线程环境下,当有多个线程对单个变量进行操作时,具有排他性,即当多个线程对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以像自旋锁一样,继续尝试。

21.线程池

●在程序启动时开辟一块内存空间,里面存放众多未死亡的线程,使用线程池管理器管理。当有线程任务时,从池中取线程,完成任务后,再将线程对象放入池中。

●线程池包含线程池管理器(创建并管理线程)、工作线程、任务接口(用于工作线程对任务进行调度)、阻塞队列(用于存放未处理的任务)。

●优点:减少了创建和销毁线程的次数,有效控制线程的最大并发数,方便线程的管理。

●参数:核心线程数,阻塞队列,最大线程数(核心线程全部用于处理任务后,新任务放到阻塞队列中,阻塞队列也满了,继续创建非核心线程处理任务),空闲线程存活时间(keepAliveTime,一般只会回收非核心线程,也可以设置回收核心线程,除了这点以外,核心线程与非核心线程没什么区别),饱和策略(默认抛弃要加入的线程)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YA0LGrsT-1650425957591)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/127.png)]

●线程池的状态:运行(Running)、关闭(Shutdown)、停止(Stop)、整理(Tidying)、结束(Terminated)

​ ■Running:接收新任务,处理队列中的任务

​ ■Shutdown:不接收新任务,处理队列中的任务

​ ■Stop:不接收新任务,不处理队列中的任务,中断正在执行的任务

​ ■Tidying:所有任务都已经终止,运行terminated方法

​ ■Terminated:terminated方法执行完成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3TgXU9q4-1650425957592)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/128.png)]

●用户通过execute()(无返回值,只能执行Runnable类型任务)、submit()(有返回值,执行Callable和Runnable类型任务,可以判断任务是否执行成功)向线程池提交任务。通过shutdown()(设置为shutDown状态)、shutdownNow()(设置为Stop状态)关闭线程池。

22.Java常用线程池

●CachedThreadPool:可缓存线程池,corePoolSize = 0,maximumPoolSize = Integer.MAX_SIZE。县城可以无限创建,需求降低时会自动回收线程,适用于执行大量短期异步任务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGcxIuuq-1650425957593)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/129.png)]

●FixedThreadPool:定长线程池,corePooleSize =maximuPoolSize 。可控制线程最大并发数,适用于负载较重的服务器。

●ScheduledThreadPool:定时线程池,适用于需要多个后台线程执行周期任务。

●SingleThreadExecutor:单线程线程池,corePoolSize = maximumPoolSize = 1。只有一个线程执行任务,遵从入队出队原则,适用于需要保证顺序执行各个任务的场景。

●ThreadPoolExecutor:自定义线程池,自定义核心数(一般为1)、阻塞队列(生产和消费速度相似,高吞吐量用LinkedBlockingQueue,吞吐量低用ArrayBlockingQueue),最大线程数(CPU密集型:n+1,IO密集型:2n),空闲线程存活时间,饱和策略(默认丢弃任务并抛出异常)。

23.Java线程池的等待任务队列

●ArrayBlockingQueue:基于数组的有界阻塞队列,长度固定,先进先出,可以指定公平和非公平(默认公平)。生产者和消费者使用同一把锁。

●LinkedBlockingQueue:基于链表的阻塞队列,先进先出,吞吐量高于前者,生产者每次存放元素会重新构造一个新节点对象,在大量并发的情况下可能会对系统GC造成一定影响。生产者和消费者使用两把锁实现同步。

●SynchronousQueue:同步队列,不是一个真正的队列,而是一种线程之间的移交机制。该队列不存储任务,当任务放在队列中时,需要有线程立即取出此任务,否则基于拒绝策略拒绝该任务。

●(各种等待队列的实现原理):https://blog.csdn.net/qq_40845019/article/details/103414046

24.Java线程池的拒绝策略

●直接丢弃任务:适用于一些无关紧要的任务

●丢弃任务并抛出异常(默认),适用于比较核心的任务,如果系统不能承受更大的并发量,可以及时发现。

●丢弃队列中的旧任务,放入新任务。

●不丢弃任务,回退到调用者,用调用者处理任务

25.线程池大小设计方法

●首先进行分析

​ ■任务的性质(CPU密集型,IO密集型,混合型)

​ ■任务的优先级

​ ■任务的执行时间

​ ■任务的依赖性(是否依赖其他系统资源)

●方法

​ ■CPU密集型任务:这类任务需要大量运算,线程很少被阻塞,CPU一直全速运行,应配置尽可能少的线程。如配置CPU个数+1的线程数(计算密集型的线程恰好在某时因为发生一个页错误或者其他原因而暂停,刚好有一个额外的线程,可以确保这个情况下CPU周期不会中断工作)

​ ■IO密集型任务:这类任务需要大量的IO,应该配置尽可能多的线程,因为IO操作不占用CPU,不要让CPU闲下来,应加大线程数量,如配置两倍的CPU个数(线程数 = CPU数*CPU使用率(1+等待时间/计算时间))IO密集型任务的等待时间?计算时间趋近于1.

​ ■混合型任务 :如果可以拆分就拆分为IO密集型和CPU密集型任务分别处理。

​ ■若任务对其他系统资源有依赖,如某个任务依赖数据库的连接返回的结果,这时候等待时间越长,CPU空闲时间越长,线程数量影设置的很大,才能很好的利用CPU。

26.常用的并发容器

●多线程的开发如果使用了非同步集合,数据就会非常混乱,所以使用的容器必须是同步的。

​ ■Vector:详情见Java集合部分

​ ■HashTable:就是HashMap+Synchronized

​ ■ConcurrentHashMap:采用分段的数组+链表实现(目前都用这个代替HashTable)

27.HashTable和ConcurrentHashMap的区别

●HashTable就是HashMap+synchronized,而concurrentHashMap底层采用分段数组+链表实现。

●HashTable的synchronized是针对整个hash表的,每次会锁住整个表让线程独占。concurrentHashMap采用锁分离技术,通过把Map分为N个segment,提供相同的线程安全,但效率高了N倍。

28.多线程交替打印,三个线程实现123123…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ESGDpyL0-1650425957593)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/130.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZWZhYnYJ-1650425957594)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/131.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3yhsY3r8-1650425957595)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/132.png)]

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/821310.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号