多进程与多线程区别?本质的区别在于每个进程拥有自己的一整套变量,而线程则共享数据。
中断线程
当线程的run方法执行方法体中最后一条语句后,并经由执行return语句返回时,或者出现在方法中没有捕获的异常时,线程将终止。通
过调用interrupt方法可以用来请求中断线程。中断线程不过是引起它的注意,被中断的线程可以决定如何响应中断。每一个线程都具有中断状
态位,当对一个线程调用interrupt方法时,线程的中断状态将被置位。每个线程都应该不时地检查这个标志,以判断线程是否被中断。但是如
果线程被阻塞,就无法检测中断状态,并且阻塞会被InterruptedException异常中断。
线程状态
New、Runnable、Blocked、Waiting、Timed waiting、Terminated
新生状态:New,线程还没有运行。
可运行状态:一旦调用start方法,线程就处于Runnable状态,线程是否运行取决于操作系统给线程提供运行的时间。
阻塞状态:当一个线程视图获取一个内部的对象锁,而该锁被其他线程持有,该线程就进入阻塞状态。当所有其他线程释放该锁,并且线
程调度器允许本线程持有它的时候,该线程将变成非阻塞状态。
等待状态:当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态(调用Object.wait或Thread.join方法,或是等待
java.util.concurrent库中的Lock或Condition时)。
计时等待状态:这一个状态将一直保持到超时期满或者接收到适当的通知(Thread.sleep,Object.wait,Thread.join,Lock.tryLock以
及Condition.await的计时版)。
终止状态:run方法正常退出或没有捕获的异常终止了run方法。
线程同步
锁对象:java.util.concurrent.ReentrantLock确保任何时刻只有一个线程进入临界区。一旦一个线程封锁了锁对象,其他任何线程都
无法通过lock语句。当其他线程调用lock时,它们将被阻塞,直到第一个线程释放锁对象。锁是可重入的,线程可以重复地获得已经持有的锁。
锁保持一个持有计数来跟踪对lock方法的嵌套调用。线程在每一次调用lock都要调用unlock是释放锁。
条件对象:管理已经获得一个锁但是却不能做有用工作的线程。ReentrantLock对象调用newCondition方法可以获得一个条件对象。
当不符合条件时调用await方法,该线程进入该条件的等待集。当锁可用时,该线程不能马上解除阻塞。当锁不可用时,它处于阻塞状态,直
到另一个线程调用同一条件上的signAll方法时为止。signAll重新激活因为这一条件而等待的所有线程。当这些线程从等待集当中移出时,它们
再次成为可运行的,调度器将再次激活它们。
synchronized关键字:Java中的每一个对象都有一个内部锁,如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方
法。内部对象锁只有一个相关条件。wait方法添加一个线程到等待集中,notifyAll方法解除等待线程的阻塞状态。
volatile域:volatile关键字为实例域的同步访问提供了一种免锁机制。
读写锁:java.util.concurrent.locks.ReentrantReadWriteLock锁,适合多线程从一个数据结构读取数据而很少线程修改其中数据。
阻塞队列
当试图向队列添加元素而队列已满,或是想从队列移出元素而队列为空的时候,阻塞队列导致线程阻塞。如果将队列当做线程管理工具来
使用,将要用到put和take方法。当试图向满的队列中添加或从空的队列中移出元素时,add、remove和element会抛出异常。使用offer、
poll和peek方法只会给出一个错误而不抛出异常。
java.util.concurrent包提供了阻塞队列:
LinkedBlockingQueue的容量是没有边界的;
LinkedBlockingDeque是一个双端的版本;
ArrayBlockingQueue在构造时需要制定容量,并且有一个可选的参数用来制定是否需要公平性;
PriorityBlockingQueue是一个带优先级的队列;
DelayQueue构造一个包含Delayed元素的误解的阻塞时间有限的阻塞队列。