一、在Java中如何唤醒一个阻塞的线程
首先,如果是IO阻塞,普通方法是无法终止线程。
第二,如果线程是因为wait,sleep等方法进入的阻塞,可以使用中断线程,并且抛出InterruptedException异常来唤醒它。
对阻塞方法的大致分类:
(1)会抛出InterruptedException异常的方法:wait,sleep,join,Lock.lockInterruptibly等,针对这类方法,我们在内部处理好异常(要么完全内部处理,要么把这个异常抛出去),然后就可以实现唤醒。
(2)不会抛InterruptedException异常的方法:Scoket的I/O,同步I/O,Lock.lock等。对于I/O类型,我们可以关闭底层通道。比如Scoket的I/O,关闭底层套接字,然后抛出异常处理就好了;同步的I/O,关闭底层Channel的通道并处理异常;对于Lock.lock方法,我们可以改成使用Lock.lockInterruptibly方法去实现。
二、多线程中submit方法和execute方法的区别
1)submit(Callable task)、submit(Runnable task, T result)、submit(Runnable task)归属于ExecutorService接口。
execute(Runnable command)归属于Executor接口。ExecutorService继承了Executor。
2)submit()方法,可以提供Future 类型的返回值;
execute()方法,无返回值。
3)sumbit()方法入参可以为Callable,也可以为Runnable;
execute()方法入参为Runnable。
三、Java并发包下常用的类有哪些
这里简单列举几个常用的类,以及作用,并不深入展开描述。
比如,Atomic,Lock,BlockingQueue,BlockingDeque,ConcurrnetMap,CountDownLatch,Cyclicbarrier,ExecutorService,CopyOnWriteList,ThreadLocal等。
1,Atomic
比如AtomicInteger,AtomicLong等类提供了多种方法,可以原子性的为参数赋值,取值,交换值(getAndSet),比较并且 设置值(CAS)(失败就重试,直到没有冲突为止)等。
2,Locks
ReentrantLock:可重入的互斥锁,即同一线程可以多次获取锁,线程之间是互斥的。使用CAS+CLH(双向链表)实现的。
ReentrantReadWriteLock:可重入的读写锁,是ReentrantLock的增强,是更细粒度的控制。在特殊场景会使用,分为readLock和writeLock,读读共享,读写和写写排他。
StrampLock:读写并发锁,适用于读远远大于写的场景。
3,BlockingQueue
阻塞队列提供了一个队列可以遵循FIFO的放入和取出的操作,如果队列满了放入就会阻塞,相反如果队列为空取出就会阻塞。BlockingQueue是一个接口类,有多种实现类,常用的有如下5个。
ArrayBlockingQueue:数组阻塞队列,是用数组实现的。是有界的,只能在初始化时指定队列容量大小。内部只有一个ReentrantLock,读和写使用一个锁,因此效率不高。
LinkedBlockingQueue:链表阻塞队列,使用链表实现的。它可以是有界的也可以是无界的,内部有两个ReentrantLock,读和写是分离的,因此性能要比ArrayBlockingQueue要高。但创建和销毁Node,高并发对GC有一定压力。
PriorityBlockingQueue:优先级阻塞队列,基于最小二叉堆实现,线程安全的无界队列。构造器传入初始值和比较器规则。根据比较器规则来对内部元素排序。
SynchronousQueue:同步阻塞队列。内部只能存放一个元素,如果满了就放入就会阻塞,相反如果为空取出就阻塞。
DelayQueue:延迟阻塞队列,无界队列。内部使用优先级阻塞队列实现,只有元素过期才能取出来,顺序按元素过期时间长短排序,队头是过期时间最长的元素,使用ReentrantLock实现线程安全。
4,BlockDeque
LinkedBlockingDeque:双端链式阻塞队列,默认是无界的,也可以指定容量。该阻塞队列同时支持
FIFO和FILO两种操作方式,队头和队尾都可以执行插入取出的操作。使用一把锁+两个条件维持队列的同步,
和ArrayBlockingQueue的原理一样。
5,ConcurrentMap
支持并发操作的Map。
ConcurrentHashMap:查看具体的内容讲解。
ConcurrentSkipListMap:
使用跳表skipList实现,可以支持排序,对应非线程安全的TreeMap是使用红黑树实现的。ConcurrentSkipListMap
适用于高并发的写操作(千万级),因为它锁住的节点少,相对于红黑树平衡造成的锁竞争,ConcurrentSkipListMap
效率更高。
6,CountDownLatch
具有计时器的功能,等待其他线程执行完毕,主线程再继续执行。
初始化指定倒计时的值,CountDownLatch latch = new CountDownLatch(3)并使用latch.await()等待执行,
当其他线程调用3此latch.countDown()就触发主线程继续。
CountDownLatch是一次性的,使用完就当前对象失效了。
7,CyclicBarrier
循环栅栏。允许定义N个线程全部执行到满足某一个条件后,再全部线程一起执行。
CyclicBarrier可以重复使用。
8,ExecutorService
线程池服务接口,有两种具体实现类。
ThreadPoolExecutor:线程池实现类。
核心参数有:
corePoolSize int 核心线程池大小
maximumPoolSize int 最大线程池大小
keepAliveTime long 线程最大空闲时间
unit TimeUnit 时间单位
workQueue BlockingQueue 线程等待队列
threadFactory ThreadFactory 线程创建工厂
handler RejectedExecutionHandler 拒绝策略
ForkJoinPool:
实现了Executor接口,支持将一个大任务分为若干个子任务交给子线程去处理,然后合并为一个结果集。
采用了分治和递归的思想。内部维护了多个队列。
9,CopyOnWriteList
CopyOnWriteList是并发场景下的List容器,适用于读远大于写的场景。相对于Vector的线程安全的List,Vector
所有方法上都有Synchronized同步锁,会造成大量的锁竞争。CopyOnWriteList使用读写分离的机制,它实现了无锁并发读,
写操作加锁,发生在新的副本上,写完后将原容器指向副本。
10,ThreadLocal
ThreadLocal用于处理同一线程数据共享的操作类。目的减少参数传递,和不同线程之间的数据隔离。
原理:内部使用静态的ThreadLocalMap对象存放元素,同一线程使用同一个ThreadLocalMap,key是ThreadLocal对象,value是存放的值。
ThreadLocalMap使用Entry数组实现,是一个弱引用,当线程被销毁时ThreadLocalMap也会被回收。