目录
多线程篇
1、什么是FutureTask?
2、什么是同步容器和并发容器的实现?
3、什么是多线程的上下文切换?
4、ThreadLocal的设计理念与作用?
5、ThreadPool(线程池)用法与优势?
6、Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
7、synchronized和ReentrantLock的区别?
8、Java Concurrency API中的Lock接口(Lock interface)是什么?对比同步它有什么优势?
9、Hashtable的size()⽅法中明明只有⼀条语句”return count”,为什么还要做同步?
10、ConcurrentHashMap的并发度是什么?
多线程篇
1、什么是FutureTask?
1 、 FutureTask可⽤于异步获取执⾏结果或取消执⾏任务的场景 。通过传⼊ Runnable 或者 Callable 的任务给 FutureTask ,直接调⽤其run ⽅法或者放⼊线程池执⾏,之后可以在外部通过 FutureTask 的 get ⽅法异步获取执⾏结果,因此,FutureTask⾮常适合⽤于耗时的计算,主线程可以在完成⾃⼰的任务后,再去获取结果。另外, FutureTask 还可以确保即使调⽤了多次run ⽅法,它都只会执⾏⼀次 Runnable 或者 Callable 任务,或者通过 cancel 取消 FutureTask 的执⾏等。2 、 futuretask 可⽤于执⾏多任务、以及避免⾼并发情况下多次创建数据机锁的出现。
2、什么是同步容器和并发容器的实现?
1 、同步容器
- 主要代表有Vector和Hashtable,以及Collections.synchronizedXxx等。
- 锁的粒度为当前对象整体。
- 迭代器是及时失败的,即在迭代的过程中发现被修改,就会抛出ConcurrentModificationException。
2 、并发容器
- 主要代表有ConcurrentHashMap、CopyOnWriteArrayList、ConcurrentSkipListMap、ConcurrentSkipListSet。
- 锁的粒度是分散的、细粒度的,即读和写是使⽤不同的锁。
- 迭代器具有弱⼀致性,即可以容忍并发修改,不会抛出ConcurrentModificationException。
3、什么是多线程的上下文切换?
1 、多线程:是指从软件或者硬件上实现多个线程的并发技术。2 、多线程的好处:
- 使⽤多线程可以把程序中占据时间⻓的任务放到后台去处理,如图⽚、视屏的下载
- 发挥多核处理器的优势,并发执⾏让系统运⾏的更快、更流畅,⽤户体验更好
3 、多线程的缺点:
- ⼤量的线程降低代码的可读性;
- 更多的线程需要更多的内存空间
- 当多个线程对同⼀个资源出现争夺时候要注意线程安全的问题。
4 、多线程的上下⽂切换:CPU 通过时间⽚分配算法来循环执⾏任务,当前任务执⾏⼀个时间⽚后会切换到下⼀个任务。但是,在切换前会保存上⼀个任务的状态,以便下次切换回这个任务时,可以再次加载这个任务的状态
4、ThreadLocal的设计理念与作用?
1、概念:线程局部变量。在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同⼀个变量,显然是不⾏的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有⼀种情况之下,我们需要满⾜这样⼀个条件:变量是同⼀个,但是每个线程都使⽤同⼀个初始值,也就是使⽤同⼀个变量的⼀个新的副本。这种情况之下ThreadLocal就⾮常适⽤,⽐如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是⼀个线程安全的变量。⽽我们每个线程都需要使⽤他,并且各⾃使⽤各⾃的。这种情况,ThreadLocal就⽐较好的解决了这个问题。
2 、原理:从本质来讲,就是每个线程都维护了⼀个 map ,⽽这个 map 的 key 就是 threadLocal ,⽽值就是我们 set 的那个值,每次线程在get 的时候,都从⾃⼰的变量中取值,既然从⾃⼰的变量中取值,那肯定就不存在线程安全问题,总体来讲, ThreadLocal 这个变量的状态根本没有发⽣变化,他仅仅是充当⼀个key 的⻆⾊,另外提供给每⼀个线程⼀个初始值。3 、 实现机制:每个Thread对象内部都维护了⼀个ThreadLocalMap这样⼀个ThreadLocal的Map,可以存放若⼲个ThreadLocal。/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
4 、应⽤场景:当很多线程需要多次使⽤同⼀个对象,并且需要该对象具有相同初始化值的时候最适合使⽤ ThreadLocal 。
5、ThreadPool(线程池)用法与优势?
1 、 ThreadPool 优点
- 减少了创建和销毁线程的次数,每个⼯作线程都可以被重复利⽤,可执⾏多个任务
- 可以根据系统的承受能⼒,调整线程池中⼯作线线程的数⽬,防⽌因为因为消耗过多的内存,⽽把服务器累趴下(每个线程需要⼤约1MB内存,线程开的越多,消耗的内存也就越⼤,最后死机)
- 减少在创建和销毁线程上所花的时间以及系统资源的开销
- 如不使⽤线程池,有可能造成系统创建⼤量线程⽽导致消耗完系统内存
2 、⽐较重要的⼏个类:
类 描述 ExecutorService 真正的线程池接口 ScheduledExecutorService 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题 ThreadPoolExecutor ExecutorService的默认实现 ScheduledThreadPoolExecutor 继承ThreadPoolExecutor的ScheduldExecutorService接口实现,周期性任务调度的类实现
3、任务执行顺序
i. 当线程数⼩于 corePoolSize 时,创建线程执⾏任务。ii. 当线程数⼤于等于 corePoolSize 并且 workQueue 没有满时,放⼊ workQueue 中iii. 线程数⼤于等于 corePoolSize 并且当 workQueue 满时,新任务新建线程运⾏,线程总数要⼩于 maximumPoolSizeiv. 当线程总数等于 maximumPoolSize 并且 workQueue 满了的时候执⾏ handler 的 rejectedExecution 。也就是拒绝策略。
6、Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
1 、 ArrayBlockingQueue 数组结构组成的有界阻塞队列:2、CountDownLatch 允许⼀个或多个线程等待其他线程完成操作;
7、synchronized和ReentrantLock的区别?
1 、基础知识
- 可重⼊锁。可重⼊锁是指同⼀个线程可以多次获取同⼀把锁。ReentrantLock和synchronized都是可重⼊锁。
- 可中断锁。可中断锁是指线程尝试获取锁的过程中,是否可以响应中断。synchronized是不可中断锁,⽽ReentrantLock则提供了中断功能。
- 公平锁与⾮公平锁。公平锁是指多个线程同时尝试获取同⼀把锁时,获取锁的顺序按照线程达到的顺序,⽽⾮公平锁则允许线程“插队”。synchronized是⾮公平锁,⽽ReentrantLock的默认实现是⾮公平锁,但是也可以设置为公平锁。
- CAS操作(CompareAndSwap)。CAS操作简单的说就是⽐较并交换。CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会⾃动将该位置值更新为新值。否则,处理器不做任何操作。⽆论哪种情况,它都会在 CAS 指令之前返回该位置的值。CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”
2 、 Synchronizedi. synchronized 是 java 内置的关键字,它提供了⼀种独占的加锁⽅式。 synchronized 的获取和释放锁由 JVM 实现,⽤户不需要显示的释放锁,⾮常⽅便。然⽽synchronized 也有⼀定的局限性:
- 当线程尝试获取锁的时候,如果获取不到锁会⼀直阻塞。
- 如果获取锁的线程进⼊休眠或者阻塞,除⾮当前线程异常,否则其他线程尝试获取锁必须⼀直等待。
3 、 ReentrantLocki. ReentrantLock 它是 JDK 1.5 之后提供的 API 层⾯的互斥锁,需要 lock ()和 unlock ()⽅法配合 try/finally 语句块来完成。ii. 等待可中断避免,出现死锁的情况(如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true ,如果等待超时,返回 false )iii. 公平锁与⾮公平锁多个线程等待同⼀个锁时,必须按照申请锁的时间顺序获得锁, Synchronized 锁⾮公平锁,ReentrantLock默认的构造函数是创建的⾮公平锁,可以通过参数 true 设为公平锁,但公平锁表现的性能不是很好。
8、Java Concurrency API中的Lock接口(Lock interface)是什么?对比同步它有什么优势?
1 、 Lock 接⼝⽐同步⽅法和同步块提供了更具扩展性的锁操作。他们允许更灵活的结构,可以具有完全不同的性质,并且可以⽀持多个相关类的条件对象。2 、它的优势有:
- 可以使锁更公平
- 可以使线程在等待锁的时候响应中断
- 可以让线程尝试获取锁,并在⽆法获取锁的时候⽴即返回或者等待⼀段时间
- 可以在不同的范围,以不同的顺序获取和释放锁
9、Hashtable的size()⽅法中明明只有⼀条语句”return count”,为什么还要做同步?
1、有问题了,可能线程 A 在执⾏ Hashtable 的 put ⽅法添加数据,线程 B 则可以正常调⽤ size ()⽅法读取 Hashtable 中当前元素的个数,那读取到的值可能不是最新的,可能线程A 添加了完了数据,但是没有对 size++ ,线程 B 就已经读取 size 了,那么对于线程B 来说读取到的 size ⼀定是不准确的。2 、⽽给 size ()⽅法加了同步之后,意味着线程 B 调⽤ size ()⽅法只有在线程 A 调⽤ put ⽅法完毕之后才可以调⽤,这样就保证了线程安全性。
10、ConcurrentHashMap的并发度是什么?
1、⼯作机制(分⽚思想):它引⼊了⼀个 “分段锁” 的概念,具体可以理解为把⼀个⼤的 Map 拆分成 N 个⼩的 segment ,根据key.hashCode ()来决定把 key 放到哪个 HashTable 中。可以提供相同的线程安全,但是效率提升 N 倍,默认提升 16 倍。2 、应⽤:当读 > 写时使⽤,适合做缓存,在程序启动时初始化,之后可以被多个线程访问;3 、 hash 冲突:
- 简介:HashMap中调⽤hashCode()⽅法来计算hashCode。由于在Java中两个不同的对象可能有⼀样的hashCode,所以不同的键可能有⼀样hashCode,从⽽导致冲突的产⽣。
- hash冲突解决:使⽤平衡树来代替链表,当同⼀hash中的元素数量超过特定的值便会由链表切换到平衡树
4 、⽆锁读: ConcurrentHashMap 之所以有较好的并发性是因为 ConcurrentHashMap 是⽆锁读和加锁写,并且利⽤了分段锁(不是在所有的entry 上加锁,⽽是在⼀部分 entry 上加锁);读之前会先判断 count ( jdk1.6 ),其中的 count 是被 volatile 修饰的(当变量被 volatile 修饰后,每次更改该变量的时候会将更改结果写到系统主内存中,利⽤多处理器的缓存⼀致性,其他处理器会发现⾃⼰的缓存⾏对应的内存地址被修改,就会将⾃⼰处理器的缓存⾏设置为失效,并强制从系统主内存获取最新的数据。),故可以实现⽆锁读。5 、 ConcurrentHashMap 的并发度就是 segment 的⼤⼩,默认为 16 ,这意味着最多同时可以有 16 条线程操作ConcurrentHashMap,这也是 ConcurrentHashMap 对 Hashtable 的最⼤优势。