
1. 并发编程的三个要素?
1)原子性
原子性是指一项或多项操作,要么全部执行且在执行过程中不被其他操作中断,要么根本不执行.
2)可见性
可见性意味着当多个线程对一个共享变量进行操作时,一个线程修改了该变量后,其他线程可以立即看到修改的结果.
如何获得可见性:
同步或锁定: 确保只有一个线程同时获取锁定执行代码. 在释放锁之前,最新值将刷新到主存储器以实现可见性.
3)秩序
已排序,即程序的执行顺序是根据代码的顺序执行的.
2. 多线程的价值?
1)利用多核CPU
多线程可以真正发挥多核CPU的优势,达到充分利用CPU的目的,通过多线程同时完成几件事而不会互相干扰.
2)防止阻塞
从程序运行效率的角度来看,单核CPU不仅不利用多线程,而且由于在单核CPU上运行多个线程而导致线程上下文切换,从而降低了整体效率该程序. 但是对于单核CPU,我们仍然需要应用多线程,以防止阻塞. 想象一下,如果单核CPU使用单个线程,只要该线程被阻塞,就可以说要远程读取某些数据,对等端没有返回并且没有设置超时时间,那么整个程序将在数据返回. 停止运行. 多线程可以防止此问题. 多个线程同时运行,即使一个线程的代码执行被阻止读取数据,也不会影响其他任务的执行.
3)易于建模
这是另一个没有明显优势的优势. 假设有一个很大的任务A,是单线程编程,那么有必要考虑很多,并且建立整个程序模型很麻烦. 但是,如果我们将这个大任务A分解为几个小任务,即任务B,任务C和任务D,构建程序模型并通过多线程分别运行这些任务,那么它将更加简单.
3. 创建线程的方法是什么?
1)继承Thread类以创建线程类
2)通过Runnable接口创建线程类
3)通过Callable and Future创建一个线程
4. 三种创建线程的方式比较?
1)通过实现Runnable和Callable接口来创建多线程.
优点是:
线程类仅实现Runnable接口或Callable接口,并且还可以继承其他类.
这样,多个线程可以共享同一个目标对象,因此非常适合多个相同的线程处理相同的资源情况,以便可以将CPU,代码和数据分离以形成清晰的模型. 面向对象思维的很好体现.
缺点是:
编程稍微复杂一些. 如果要访问当前线程,则必须使用Thread.currentThread()方法.
2)通过继承Thread类创建多个线程
优点是:
编写起来很简单. 如果需要访问当前线程,则不需要使用Thread.currentThread()方法,可以直接使用它来获取当前线程.
缺点是:
Thread类继承了Thread类,因此无法继承其他父类.
3)Runnable和Callable之间的区别
5. 线程状态流程图
线程生命周期和五个基本状态:

Java线程具有五个基本状态

1)新建状态(新建): 创建线程对象对时,它将进入新状态,例如: 线程t = new MyThread();
2)就绪状态(可运行): 调用线程对象的start()方法(t.start();)时,线程进入就绪状态. 处于就绪状态的线程仅表示该线程已准备就绪,可以随时等待CPU调度执行,而不是意味着该线程将在执行t.start()之后立即执行;
3)运行状态: 当CPU开始将线程调度为就绪状态时,此时可以实际执行该线程,即进入运行状态. 注意: 就绪状态是进入运行状态的唯一入口点,也就是说,如果线程要进入运行状态以执行,则必须首先处于就绪状态; </ p>
4)阻塞(Blocked): 处于运行状态的线程出于某种原因暂时放弃使用CPU的权利并停止执行. 此时,它进入阻塞状态,直到进入就绪状态,才有机会重新进入. 由CPU调用以进入运行状态. 根据阻塞的不同原因,阻塞状态可以分为三种类型:
1. 等待阻塞: 处于运行状态的线程执行wait()方法使线程进入等待阻塞状态; </ p>
2. 同步阻塞—线程无法获取同步锁(由于该锁已被其他线程占用),它将进入同步阻塞状态; </ p>
3. 其他阻塞—通过调用线程的sleep()或join()或发出I / O请求java多线程避免死锁,线程将进入阻塞状态. 当sleep()状态超时,join()等待线程终止或超时或I / O处理完成时,线程将重新进入就绪状态.
5)死状态: 由于异常,线程完成执行或退出run()方法,并且线程结束其生命周期.
6. 什么是线程池?有哪些创建方法?
线程池用于预先创建几个线程. 如果有要处理的任务,则线程池中的线程将处理该任务. 处理之后,该线程将不会被销毁,而是等待下一个任务. 因为创建和销毁线程会消耗系统资源,所以当您要频繁创建和销毁线程时,可以考虑使用线程池来提高系统性能.
java提供了用于创建线程池的java.util.concurrent.Executor接口的实现.
创建四个线程池:
(1)newCachedThreadPool创建一个可缓存的线程池
(2)newFixedThreadPool创建一个固定长度的线程池来控制并发线程的最大数量.
(3)newScheduledThreadPool创建一个固定长度的线程池,该池支持计划的和定期的任务执行.
(4)newSingleThreadExecutor创建一个单线程线程池,它将仅使用单个工作线程来执行任务.
7. 线程池的优点?
1)重用现有线程以减少对象创建和销毁的开销.
2)可以有效控制并发线程的最大数量,提高系统资源的利用率,避免过多的资源竞争和阻塞.
3)提供诸如定期执行,定期执行,单线程和并发编号控制之类的功能.
8. Java中的同步收集和并发收集有什么区别?
同步收集类:
并发收集类:
9. 同步集和并发集的区别
同步集合和并发集合都为多线程和并发提供了合适的线程安全集合,但是并发集合具有更高的可伸缩性. 同步收集比并发收集要慢得多. 主要原因是锁. 同步集合锁定整个May或List,而并发集合(例如ConcurrentHashMap,
整个Map分为几个片段,只有相关的片段被锁定,同时允许多个线程访问其他未锁定的片段(红色和黑色的树被添加到JDK1.8版本的底部).
10. 常用的并发工具是什么?
11. CyclicBarrier和CountDownLatch的应用场景?
CountDownLatch: 一个线程(或多个线程),等待另外N个线程完成某些操作,然后才能执行该操作. CyclicBarrier: N个线程互相等待. 在任何线程完成之前,所有线程必须等待.
CountdownLatch使用方案:
在某些应用程序中,您需要先等待某个条件满足要求,然后才能执行后一件事情;同时,当线程完成时,也将触发该事件以便执行后续操作,这时您可以使用CountDownLatch.
CyclicBarrier使用场景
CyclicBarrier可以用于多线程计算数据中,并最终合并应用场景的计算结果.
12. CyclicBarrier和CountDownLatch之间的区别
1)CountDownLatch仅仅意味着一个线程等待,直到它等待的其他线程完成,并且调用countDown()方法发出通知,当前线程可以继续执行.
2)CyclicBarrier是所有线程都等待,直到所有线程准备好进入await()方法,所有线程才同时开始执行!
3)CountDownLatch的计数器只能使用一次. 可以使用reset()方法重置CyclicBarrier计数器. 因此CyclicBarrier可以处理更复杂的业务场景,例如,如果计算错误,则可以重置计数器并让线程再次执行.

4)CyclicBarrier还提供了其他有用的方法,例如getNumberWaiting方法来获取被CyclicBarrier阻塞的线程数. isBroken方法用于了解阻塞的线程是否被中断. 如果被中断,则返回true,否则返回false.
13. 同步的作用是什么?
在Java中,synced关键字用于控制线程同步,即在多线程环境中,同步代码段不能同时由多个线程执行.
可以将同步添加到一段代码或方法中.
14. 易失性关键字的作用
对于可见性,Java提供了volatile关键字以确保可见性.
当共享变量被volatile修改时,它将确保修改后的值将立即更新到主内存中,而当需要读取其他线程时,它将去内存中读取新值.
从实践的角度来看,挥发物的重要作用是与CAS结合以确保原子性. 有关详细信息,请参见java.util.concurrent.atomic包下的类,例如AtomicInteger.
15. 什么是CAS
CAS是比较和交换的缩写,这就是我们所说的比较交换.
cas是基于锁的操作,并且是乐观锁. 在Java中,锁分为乐观锁和悲观锁. 悲观锁会锁定资源,并等待先前获得该锁的线程释放该锁,然后下一个线程才能访问它. 乐观锁定采取宽泛的态度java多线程避免死锁,并以某种方式处理资源而不进行锁定,例如通过向记录添加版本来获取数据. 与悲观锁定相比,性能得到了大大提高.
CAS
该操作包含三个操作数-
存储位置(V),预期原始值(A)和新值(B). 如果内存地址中的值与A中的值相同,则将内存中的值更新为B. CAS通过无限循环获取数据. 如果在第一轮循环中,线程a所获取的地址中的值被线程b所修改,则线程a需要旋转,并且直到下一个周期才可能执行它.
java.util.concurrent.atomic包下的类主要使用CAS操作(AtomicInteger,AtomicBoolean,AtomicLong)实现.
16. CAS问题
1)CAS很容易引起ABA问题. 线程a将值更改为b,然后将其更改为a. 目前,CAS认为没有任何变化,但实际上已经发生了变化. 可以通过版本号标识此问题的解决方案,并且每个操作的版本都增加1. . 在java5中,提供了AtomicStampedReference来解决该问题.
2)无法保证代码块的原子性
由CAS机制保证的变量原子操作的知识不能保证整个代码块的原子性. 例如,如果您需要确保自动更新这三个变量,则必须使用synced.
3)CAS导致CPU利用率增加. 我之前说过,CAS中有一个循环判断过程. 如果线程尚未获得状态,则将始终占用CPU资源.
17. 什么是未来?
在并发编程中,我们经常使用非阻塞模型. 在多线程的先前三个实现中,无论是继承线程类还是实现可运行接口,都不能保证将获得先前的执行结果. 通过实现Callback接口并使用Future,您可以接收多个线程的执行结果.
将来表示可能尚未完成的异步任务的结果. 任务成功或失败之后,可以在此结果中添加回调以进行相应的操作.
18. 什么是AQS
AQS是AbustactQueuedSynchronizer的缩写. 它是Java改进的低级同步工具类. 它使用int类型的变量指示同步状态,并提供一系列CAS操作来管理此同步状态.
AQS是用于构建锁和同步器的框架. 使用AQS可以轻松高效地构造大量广泛使用的同步器,例如ReentrantLock,Semaphore和其他诸如ReentrantReadWriteLock,SynchronousQueue和FutureTask. 等等都是基于AQS.
AQS支持两种同步方法:
1. 独家
2. 共享
这对用户实现不同类型的同步组件非常方便,例如,排他类型(例如ReentrantLock),共享类型(例如Semaphore,CountDownLatch)以及组合类型(例如ReentrantReadWriteLock). 简而言之,AQS提供了使用的基础支持,用户可以自由发挥如何组装和实现它.
19. 什么是ReadWriteLock
首先,请澄清一下. 不是说ReentrantLock不好. 如果使用ReentrantLock,则可能是防止线程A写入数据而线程B读取数据而导致的数据不一致,但是以这种方式,如果线程C正在读取数据而线程D也正在读取数据,则读取数据不会改变数据,无需锁定,但仍处于锁定状态,从而降低了程序的性能.
因此,ReadWriteLock诞生了. ReadWriteLock是一个读写锁接口,ReentrantReadWriteLock是ReadWriteLock接口的特定实现,它实现了读写分离,共享读锁,写锁是互斥的,读写不会互斥,读写,写作和阅读,写作和写作是互斥的,从而提高了阅读和写作的性能.
20. 什么是FutureTask
如前所述,FutureTask代表异步计算任务. 可以将具体的Callable实现类传递到FutureTask中,该类可以等待此异步操作任务的结果获得,判断它是否已完成,取消任务和其他操作. 当然,由于FutureTask也是Runnable接口的实现类,因此FutureTask也可以放入线程池中.
21. 同步和ReentrantLock之间的区别
Synchronized是相同的关键字,就好像ReentrantLock是一个类一样,这是两者之间的本质区别. 由于ReentrantLock是一个类,因此它提供的功能比同步功能越来越多. 它可以被继承,可以具有方法,并可以具有各种类变量. ReentrantLock比同步的可伸缩性体现在以下几点: <
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-236046-1.html
闯一下就不得了