1.线程基本知识:
线程的声明周期中的6个状态:
(1)NEW 被创建
至今尚未启动的线程处于这种状态。
(2)RUNNABLE 可运行
正在 Java虚拟机中执行的线程处于这种状态。处于可运行状态的某一线程正在 Java虚拟机中运行,但它可能正在等待操作系统中的其他资源,比如处理器。
(3)BLOCKED 被阻塞
受阻塞并且正在等待监视器锁的某一线程的线程状态。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用 Object.wait 之后 再次进入同步的块/方法。
(4)WAITING
无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。某一线程因为调用下列方法之一而处于等待状态:
1、不带超时值的 Object.wait
2、不带超时值的 Thread.join
3、LockSupport.park
处于等待状态的线程正等待另一个线程,以执行特定操作。 例如,已经在某一对象上调用了 Object.wait() 的线程正等待另一个线程,以便在该对象上调用 Object. notify() 或 Object.notifyAll()。已经调用了 Thread.join() 的线程正在等待指定线程终止。
1、不带超时值的 Object.wait
2、不带超时值的 Thread.join
3、LockSupport.park
处于等待状态的线程正等待另一个线程,以执行特定操作。 例如,已经在某一对象上调用了 Object.wait() 的线程正等待另一个线程,以便在该对象上调用 Object. notify() 或 Object.notifyAll()。已经调用了 Thread.join() 的线程正在等待指定线程终止。
(5)TIMED_WAITING 计时等待
具有指定等待时间的某一等待线程的线程状态。某一线程因为调用以下带有指定正等待时间的方法之一而处于定时等待状态:
1、Thread.sleep
2、带有超时值的 Object.wait
3、带有超时值的 Thread.join
4、LockSupport.parkNanos
5、LockSupport.parkUntil
1、Thread.sleep
2、带有超时值的 Object.wait
3、带有超时值的 Thread.join
4、LockSupport.parkNanos
5、LockSupport.parkUntil
(6)TERMINATED 被终止
已终止线程的线程状态。线程已经结束执行。
线程属性:
(1)线程优先级:1-10 默认5
(2)守护线程:为其他线程提供服务的线程。 可调用setDaemon(true)
(3)线程组
(4)处理未捕获异常:不被检测的异常会进入线程的未捕获异常处理器
2.同步
两个或两个以上的线程需要共享对同一数据的存取,会产生竞争条件,这个时候我们需要使用同步。
(1)使用锁对象:RentrantLock
条件对象:线程已经获得了锁,但是不满足了某些条件,需要使用条件对象await()阻塞当前线程,等待其他线程的条件对象使用signalAll()唤醒执行所有相关锁
的,signal()随机挑选其中一个。
(2)使用synchronized 关键字。使用锁对象可以有多个条件,synchronized关键字只能使用一个条件,如果不满足条件条用wait()阻塞线程。
(3)监视器:java设计者采用了很不精确的监视器概念,在JAVA虚拟机中,每个对象(Object和class)通过某种逻辑关联监视器,为了实现监视器的互斥功能,每个对象
(Object和class)都关联着一个锁(有时也叫“互斥量”),这个锁在操作系统书籍中称为“信号量”,互斥(“mutex “)是一个二进制的信号量。每个方法和代码块可以使用
synchronized加锁,还可以条用wait/notify/notifyall来访问条件变量
(4)volatie关键字 volatile让变量每次在使用的时候,都从主存中取,保证安全读取了。而不是从各个线程的“工作内存”。具有一点 synchronized 的意思,但是还是不能
保证原子性。请参照链接
点击打开链接
(5)使用final修饰符
(6)使用线程局部变量 使用ThreadLocal为各线程提供各自的实例
(7)ReentrantReadWriteLock类 读写锁 很多线程都的多写的少使用读写锁
3.阻塞队列
有时候我们不一定使用枷锁来完成来保证线程安全,完全可以使用一个或者多个队列以优雅安全的方式将线程形式化。它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略。详细请参考
点击打开链接
4.线程安全集合
java.util.concurrent包中提供了线程安全的集合、映射表和队列:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentSkipLinkedQueue.
java早期的Vector和Hashtable线程安全策略基本新版本已经不提倡,废除了
5.Callable和Future
创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口。这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。详细请看
点击打开链接
6.执行器和线程池
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
从Java5开始,Java内建支持线程池.Java5新增了一个Executors工厂类来产生线程池.如下
- newCachedTheradPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将被缓存在线程池中.
- newFixedTheradPool(int threadNum):创建一个可重用,有固定线程数的线程池.
- newSingleThreadExecutor():等同上面方法传入的参数为1.
- newScheduledThreadPool(int num):创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务.num是指池中所保存的线程数,即使线程是空闲的也被保存在线程池内.
- newSingleThreadScheduledExecutor():创建只有一个线程的线程池,它可以在指定延迟后执行线程任务
前3个方法返回都是一个ExecutorService对象,该对象代表一个线程池.而且是立即执行.该对象还可以控制任务组的执行
后2个方法返回都是一个ScheduledExecutorService对象,它是ExecutorService的子类,可以指定延迟后执行线程任务.
后2个方法返回都是一个ScheduledExecutorService对象,它是ExecutorService的子类,可以指定延迟后执行线程任务.
线程池接口的继承关系