程序、进程、线程

  • 程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  • 进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:
    1. 有它自身的产生、存在和消亡的过程——生命周期
    2. 程序是静态的,进程是动态的
    3. 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
  • 线程(thread):进程可进一步细化为线程,是一个程序内部的一条执行路径。
    1. 若一个进程同一时间并行执行多个线程,就是多线程
    2. 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小
    3. 一个进程中的多个线程共享相同的内存单元内存地址空间,它们从同一堆中分配对象,可以访问相同的变量和对象。
    4. 这就使得线程间通信更简便、高效。但多 个线程操作共享的系统资源可能就会带来安全的隐患。

线程生命周期

线程状态:

  1. new~新创建
  2. Runable~可运行(即调用start()方法)
  3. Blocked~被阻塞
  4. Waitiing~等待
  5. Timed waiting~计时等待
  6. Terminated~被终止

获取一个线程的当前状态,getState()

  • 一个可运行线程可能正在运行也可能没有运行,取决于操作系统分配的时间
  • 运行中的线程被中断,目的是为了让其他线程获得运行机会
  • 抢占式调度,协作式调度(手机小型设备,只有线程调用yield方法、或者被阻塞或等待时,线程才失去控制权)

创建线程

  1. 继承Thread类,重写run方法
  2. 实现Runnable接口,重写run方法
  3. 创建线程池,获取线程执行
  4. Timer 创建延时执行

注意:直接调用run()方法,只是主线程执行一个方法,而不会创建线程

中断线程

终止线程

  1. run方法执行到return语句,或者run方法中有异常未捕获会中断线程,将终止线程
  2. 调用stop(),已经弃用;

中断线程

  1. 使用interrupt(),请求中断线程,Thread.currentThread获取当前线程,然后调用isInterrupt检测
  2. sleep或wait中的线程,再被调用中断,将产生中断异常
  3. 中断置位后的线程调用sleep(),不会进行睡眠,而是被唤醒执行,并抛异常,需要捕获异常

建议:中断异常在方法中抛出,而不是catch;

被阻塞线程或等待线程

  1. 获取内部对象锁
  2. 自定义:Java.util.concurrent锁
  3. 它进入等待状态,等待另一个线程通知(notify,single),
  4. Thread一些方法
  • await()\sleep()
  • void join()~等待终止指定线程
  • void stop()~停止该线程(过时)
  • suspend()~暂停该线程,resum()恢复线程,仅在suspend()之后调用

终止线程

1、run方法正常结束(return语句)
2、未捕获异常而终止


线程属性

线程优先级

  1. 默认继承父类线程优先级
  2. setPriority()设置线程(MIN_PRIORITY=1,默认优先级:NORM_PRIORITY=5,MAX_PRIORITY=10)

注意:只是执行概率设置

  • 线程优先级依赖于系统,即虚拟机依赖于主机平台的线程实现机制
  • 不要将程序的正确性太依赖于线程优先级
  • 高优先级没有进入非活动状态,低优先级永远不会执行

    守护线程

  1. 只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束
  2. thread.setDaemon(true);~在线程启动前调用,使这个线程具有最低的优先级
  3. 所以守护线程不可以访问固有资源如文件、数据库

未捕获异常的处理

未捕获异常的处理器

原因:run()方法不能抛出任何受查异常,非受查异常会导致线程终止

  • 父类方法没有异常,若方法有异常子类需要异常处理)

    1. Thread.UncaughtExceptionHandler是函数式接口
    • 如果不为线程安装处理器,由线程组处理

      1. //创建处理器
      2. public class ThreadTest implements Runnable, Thread.UncaughtExceptionHandler {
      3. @Override
      4. public void uncaughtException(Thread t, Throwable e) {
      5. ...//不是默认处理器,处理器为空
      6. }
      7. public static void main(String[] args) {
      8. ThreadTest threadTest = new ThreadTest();
      9. Thread thread = new Thread(threadTest);
      10. thread.setUncaughtExceptionHandler(threadTest);
      11. //默认处理器
      12. Thread.setDefaultUncaughtExceptionHandler(threadTest);
      13. }

      线程组:

  • 统一管理线程的集合,不建议用自己的方式使用线程组
  • java.lang.ThreadGroup~~当此线程组中的线程因未捕获的异常而停止时,由Java虚拟机调用,并且该线程没有安装特定的Thread.UncaughtExceptionHandler

同步

一、ReentrantLock

  1. Runnable r = ()->{
  2. ReentrantLock reentrantLock = new ReentrantLock();
  3. reentrantLock.lock();
  4. try{
  5. ....
  6. }finally{
  7. reentrantLock.unlock();
  8. }
  9. };
  1. finally:如果有异常也能释放锁,不会阻塞
  2. try不能写带资源的语句,无法正常工作
  3. ReentrantLock(boolean fiar)公平锁

情景:需要使用一个添加对象来管理那些已经获得一个锁但却不能做有用工作(需要满足某一条件)的线程
即依赖另一个线程处理条件

Lock与newContition()

简介:当一个线程调用await();~进入等待集,另一个线程调用signa(); 后才可解除阻塞

  1. 创建newContition()对象

Condition condition = reentrantLock.newCondition()

  1. 设置等待集

condition.await();
前提条件:当前线程已经成功获得与该条件对象绑定的锁,否则会抛出IllegalMonitorStateException。
简介:使当前线程加入 await() 等待队列中,并释放当锁;当其他线程调用signal()会重新请求锁。与Object.wait()类似
注意:结束等待的唯一方法是其它线程调用该条件对象的signal()signalALL()方法
等待过程中如果当前线程被中断,该方法仍然会继续等待,同时保留该线程的中断状态。
condition.signalAll();~解除等待集的全部线程、
condition.signal();~随机解除某个线程

二、synchronized与wait()/notify()

简介:Java每个对象都有一个内部锁,方法声明关键字,使对象锁保护整个方法

  • 静态同步方法,当该方法被调用时,其他静态同步方法只能被当前线程调用

局限性:

  1. 试图获得锁时不能设置超时
  2. 不能中断试图获取锁的线程

使用:

  1. 修饰代码块的时候需要一个对象作为锁的对象.
  2. 在修饰方法的时候默认是当前对象作为锁的对象.
  3. 在修饰类时候默认是当前类的Class对象作为锁的对象.

三、监视器概念

  1. 只包含私有域的类
  2. 类有一个相关的锁
  3. 该锁对所有方法进行加锁(synchronized)

四、同步变量

volatile 域

  1. 防止一个变量被多个线程设置、读取出问题(或者使用锁)
  2. volatile 变量不能确保值被反转成功,或不被中断

final修饰变量

  1. 线程在构造函数加载完后才能使用该修饰的变量
  2. 并不安全,也需要同步操作

五、申请锁

简介:线程在调用lock方法来获得另一个线程所持有的锁的时候,很可能发生阻塞。应该更加谨慎地申请锁

java.util.concurrent.locks.Lock包

  1. boolean tryLock方法试图申请一个锁,在成功获得锁后返回true,否则,立即返回false,且该线程可以立即离开去做其他事情
  • tryLock(long time,TimeUnit unit)尝试获得锁,不能超过阻塞时间;该方法如果线程在等待锁期间被中断,将抛出InterruptedException异常
  • lockInterruptibly()超时设为无限。如果线程被中断,抛出一个InterruptedException异常。

java.util.concurrent.locks.Condition

  1. boolean await(long time,TimeUnit unit)进入该条件的等待集,
  • 直到线程从等待集中移出或等待了指定的时间之后才解除阻塞。
  • 如果因为等待时间到了而返回就返回false,否则返回true
  • 等待的线程被中断,将抛出一个InterruptedException异常
  1. void awaitUninterruptibly()进入该条件的等待集
  • 直到线程从等待集移出才解除阻塞。
  • 如果线程被中断,该方法不会抛出InterruptedException异常。

六、读写锁

简介:对读线程和写者线程依然是互斥访问的
java.util.concurrent.locks.ReentrantReadWriteLock

使用读/写锁的必要步骤:

  1. 构造一个ReentrantReadWriteLock对象
  2. 创建读写锁ReentrantReadWriteLock.ReadLockORReentrantReadWriteLock.WriteLock
  3. 对读写方法分别加读、写锁