Java并发之常见问题
Posted 狗哥狗弟齐头并进
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java并发之常见问题相关的知识,希望对你有一定的参考价值。
这里写目录标题
- 1 Java中守护线程跟本地线程有什么区别?
- 2 线程和进程的区别?
- 3 什么是多线程的上下文切换
- 4 什么是死锁?如何防止死锁?
- 5 Java中用到的线程调度算法?
- 6 为什么使用Executor框架?
- 7 Executor和Executors的区别?
- 8 原子操作类?
- 9 Lock接口是什么?对比同步有什么优势?
- 10 什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?
- 11 什么是Callable和Future?
- 11 什么是FutureTask?使用ExecutorService启动任务。
- 12 CycliBarriar和CountdownLatch有什么区别?
- 13 join方法可以使得一个线程在另一个线程执行完之后再去执行。
- 14 lock 中的api
1 Java中守护线程跟本地线程有什么区别?
任何线程都可以设置为守护线程和用户线程,通过Thread.setDaemon(true)为守护线程,false为用户线程。但是注意得是:这个操作必须要在Thread.start()方法之前。
他俩得区别就是:当虚拟机中只剩垃圾守护线程得时候,jvm就会离开。守护线程是为用户线程服务的。用户线程是由程序创建的。
2 线程和进程的区别?
共享资源: 线程之间共享同一个进程下的地址空间以及资源,而进程之间为单独的地址空间。且进程之间的资源是相互独立的。
执行: 线程不能单独执行,必须依赖于进程。进程可以单独执行。
并发:都支持并发。
切换:进程之间进行上下文切换的时候,耗费的资源大。当涉及到频繁的切换时,使用线程要好一点.
3 什么是多线程的上下文切换
cpu执行程序是按cpu时间片来分配调度时间的,一个进程中包含了多个线程,每个时间片上最多只能运行一个线程,操作系统通过调度cpu时间片,让多个线程并发的执行,外界看起来好像多个线程是同时执行的。在每个cpu之间涉及到的切换,也就是线程之间的切换,即为上下文切换。为了让线程都有执行的机会,必须调度。
java中上下文切换的时候主要使用程序计数器来保存线程执行到哪一步,以便切换回来的时候可以继续执行,而不出错。
4 什么是死锁?如何防止死锁?
死锁就是互相占有对方的资源不放手,死锁造成的原因有四种:
- 互斥条件:同一个资源在同一时刻只能被一个线程所持有。
- 请求于保持条件:当占有锁的线程去请求其他资源的时候,对已经获取的资源不放手。
- 不被剥夺条件:获取资源的线程,只要不主动释放, 就不会被剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
防止死锁就破坏后三个条件。
破坏请求与保持条件: 一次性请求多个资源。
破坏循环等待:获取锁和释放锁按顺序进行。
破坏不被剥夺条件:如果请求其他资源请求不到,可以主动释放。
5 Java中用到的线程调度算法?
计算机通常只有一个CPU,在任意时刻只能执行一条机器指令,每个线程只有获得cpu的使用权才能执行指令,所谓的多线程的并发与逆行其实是指从宏观上看,各个线程轮流获得cpu的使用权,分别执行各自的任务。在运行池中,回有多个处于就绪状态的线程在等待CPU,Java虚拟机的一项任务就是负责线程的调度。
有两种调度模型: 分时调度模型和抢占式调度模型
分时调度模型是指让所有的线程轮流获得cpu的使用权,并且平均分配每个线程占用的cpu的时间片这个也比较好理解。
Java虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。处于运行状态的线程一直运行,不得不放弃CPU。
6 为什么使用Executor框架?
- 每次执行任务都new Thread()会比较耗费系统性能,创建一个线程是比较耗时耗资源的。
- new的线程缺乏管理,线程之间的上下文切换很野。可以无限制的创建,可能会导致系统的瘫痪。
- 使用Thread()不利于扩展
7 Executor和Executors的区别?
- Executor是用来执行线程任务的。
- Executors是用来创建不同的线程池的,以便满足不同的需求。
8 原子操作类?
AtomicInteger、atomicLong、Atomicboolean、AtomicReference
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater、AtomicLongFieldUpdater
解决ABA问题的原子类:
AtomicMarkableReference:通过引入一个boolean来反映中间有没有变过。
AtomicStampedReference:通过引入一个int来累加来反应中间有没有变过。
9 Lock接口是什么?对比同步有什么优势?
Lock接口比同步方法和同比代码块更具有扩展性。
Lock提供了无条件的、可轮询的(tryLock)、定时的(trylock带参数)、可中断的、可多田间队列的所操作。Lock的实现类基本都支持公平锁和非公平锁。当然大部分情况下,非公平锁是高效的选择。
10 什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?
阻塞队列是一个支持两个附加操作的队列。
① 在队列为空时,获取元素的线程会等待阻塞队列非空。
⑥ 当队列满时,存储元素的线程会等待队列可用。
LinkedBlockingDeque 链表实现的双向阻塞队列
Queue是单向,Dequeue是双向。
11 什么是Callable和Future?
Callable是创建线程的一个方式,只不过callable带有异常以及返回值。
这个返回值可以被Future拿到。
Futur接口表示异步任务,是还没有完成的任务给出的未来结果。Callable用来产生结果,Future接受结果。
11 什么是FutureTask?使用ExecutorService启动任务。
FutureTask表示一个可以取消的异步任务。可以交给Executors执行。
12 CycliBarriar和CountdownLatch有什么区别?
CyclicBarrier可以重复使用,而CountdownLatch不能重复使用
java的concurrent包里面的CoutDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去减这个计数器里面的值。你可以向CountDownLatch对象设置一个数字作为计数值。然后又两个方法 await() 调用方法一直阻塞,知道计数为0、countdown()方法会将计数值减1.
13 join方法可以使得一个线程在另一个线程执行完之后再去执行。
public class thread1
public static void main(String[] args) throws InterruptedException
tt t1 = new tt();
tt t2= new tt();
tt t3= new tt();
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
static class tt extends Thread
@Override
public void run()
for (int i = 0; i < 100; i++)
System.out.println(Thread.currentThread().getName() + " :" + i);
14 lock 中的api
lock: lock是正常的获取锁,获取不到锁就等待
trylock:与lock一样 获取成功返回true,获取失败返回false
trylock(参数1,参数2):获取锁获取失败会等待指定的时间
interupt:线程获取不到锁,进入等待状态,可以调用线程的interupt中断线程的等待。
以上是关于Java并发之常见问题的主要内容,如果未能解决你的问题,请参考以下文章