初探Java多线程

基础理论篇学习笔记

1.什么是进程

  • 进程是程序运行和资源分配的基本单位,一个程序至少一个进程,一个进程至少一个线程。

  • 多个进程的内部数据和状态是完全独立的而多个线程是共享一个内存空间和一组系统资源,有可能互相影响


2.什么是线程

  • 线程是程序内部的控制流,只能使用分配给线程 的资源和环境
  • 线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换负担要小。
  • 线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小能独立运行的基本单位。

3.多线程编程的目的

  • 多线程编程的目的,就是 最大限度地利用CPU资源,当某一线程的处理不需要占用CPC而和I/O等资源打交道时,让需要占用CPU资源的其他线程有机会获得CPU资源,从根本上,这就是多线程编程的最终目的。

4.多线程概念介绍

  • 一个进程可以包含多个线程。
  • 一个程序实现多个代码同时交替运行就需要产生多个线程。
  • CPU随机的抽出时间,让我们的程序一会做这件事情,一会做另外一件事情。
  • 同期其他大多数编程语言不同,Java内置支持多线程编程(multithreaded progranmming)。多线程程序包包含两个或两条以上并发运作的部分,吧程序中每个这种的部分都叫做一个线程(thread),每个线程都独立的执行路经,因此多线程是多任务处理的一种特殊形式。
  • 多任务处理被所有的现代操作系统所支持。然后,多任务处理有两种截然不同的类型,基于进程和基于线程。
    • 基于进程
      • 基于进程的多任务处理是更熟悉的形式,进程(process)本质上是一个执行的程序。因此基于进程的多线程任务处理的特点是允许你的计算机同时运行两个或更多的程序。
    • 基于线程
      • 基于线程(thread-based)的多任务处理环境中,线程是最小的执行单位。这意味着一个程序可以执行两个或则多个任务的功能。
    • 多线程程序比多进程程序需要更少的管理资源。
      • 进程是重量级的任务,需要分配给他们的独立空间地址。进程之间通信是昂贵和受限的。进程之间的转换也是很需要花费的。另一方面,线程是轻量级的选手,它们共享相同的地址空间并且共享同一进程,线程之间通信是轻量级的,线程的转换也是轻量级的。
    • 线程的实现
      • 1.两种方法均需要执行线程start方法作为线程分配必须的系统资源、调度线程运行并执行线程的run方法。
      • 2.在具体应用中,采用哪种方法来构造线程体要试情况而定。通常,当一个线程继承了另一个类,应该应该使用第二种方法,即使实现runnable接口。
      • 3.线程的消亡不能通过调用一个Trread.stop方法,而是让线程自然消亡。

5.线程的生命周期

线程的生命周期

  • 一个线程的消亡过程。

  • 线程的生命周期状态。

    • 创建状态
    • 可运行状态。
    • 运行状态
    • 不可运行状态(阻塞状态)。
    • 消亡状态。

线程的状态

创建状态

  • 当用new操作创建一个新的线程对象的时候,该线程处于创建状态。
  • 处于创建状态的线程只是一个空洞线程对象,系统不为它分配资源。

可运行状态

  • 执行线程的start()方法将为线程分配必须的系统资源,安排其运行。并调用线程体run()方法。这样就使得该线程处于可运行(Runnable)状态。
  • 这一状态并不是运行中状态(Runnable),因为线程也许实际上并未真正运行。

运行状态

  • 如果就绪的状态线程获取cpu资源,就可以run,此时线程便是运行状态,处于运行状态的线程可以变为阻塞状态、就绪状态、和死亡状态。

不可运行状态

  • 当发生以下事件时,处于运行状态的线程进入到不可运行的状态。

    • 调用线程类sleep()方法。

      • 1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        /**
        * Causes the currently executing thread to sleep (temporarily cease
        * execution) for the specified number of milliseconds, subject to
        * the precision and accuracy of system timers and schedulers. The thread
        * does not lose ownership of any monitors.
        *
        * @param millis
        * the length of time to sleep in milliseconds 睡眠的时间,以毫秒为单位
        *
        * @throws IllegalArgumentException
        * if the value of {@code millis} is negative 如果millis是负数
        *
        * @throws InterruptedException
        * if any thread has interrupted the current thread. The
        * <i>interrupted status</i> of the current thread is
        * cleared when this exception is thrown.
        */
        public static native void sleep(long millis) throws InterruptedException;
    • 线程调用wait方法等待特定条件的满足。

    • 线程输入/线程阻塞。

    • 返回可运行状态

      • 处于睡眠的线程在指定时间后
      • 如果线程在等待某一个条件,另一个对象必须通过notify()或则notifyAll()方法通知等待线程条件的改变。
      • 如果线程是因为输入/阻塞,等待输入/输出完成。

消亡状态

  • 当线程的run方法执行完成之后,该线程就自然消亡了。

6.线程优先级

  • 设置优先级是为了在多线程环境中便于系统对线程调度,优先级高的线程将优先执行。

    • 一个线程的优先级遵从以下原则。
      • 线程创建时,子继承父的优先级。
      • 线程创建后,可用过调用setPriority()方法改变优先级。
      • 线程的优先级是1-10之间的正整数。
        • 1 - MIN_PRIORITY
        • 10 - MAX_PRIORITY
        • 5 - NORM_PRIORITY
  • 线程的优先级策略

    • 线程调度器选择优先级最高的线程运行.但是,如果发生以下情况,就会终止线程的运行.
      • 线程体中调用了yieid()方法,让出了对CPU的占用权。
      • 线程体中调用sleep()方法,使线程进入了睡眠状态。
      • 线程由I/O操作而受阻塞。
      • 另一个更高优先级的线程出现。
      • 在支持时间片段系统中,该线程的时间片用完。

7.线程的同步

  • 在多线程环境中,可能会出现两个甚至多个线程试图同时访问一个有限的资源。必须对这种潜在的资源冲突进行预防。
    • 解决方案:在线程使用一个资源时为其加锁即可。访问资源的第一个线程为其上锁以后,其他线程比便不能在使用那个资源。除非被解锁。
  • 在线程环境中,关于成员变量与局部变量;如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时候,他们对该成员变量是彼此影响到(也就是说一个线程对成员变量的改变会影响另一个到另一线程)。
  • 不能依靠线程优先级来决定线程的执行。
  • 同步到实现方式
  • synchronized 关键字;当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
  • Java中方锁。
    • java中每个对象都有一个锁(lock)或者叫监视器(monitor),当访问一个对象synchronized方法时,表示将该对象上锁,此时其他任何线程在去访问该synchronized方法了,直到之前那个线程执行方法完毕后(或者抛出异常),那么该对象的锁释放掉。其他线程才有可能再去访问synchronized方法。
    • 如果一个对象中有多个synchronized方法,某一时刻某个线程进入了该对象中的synchronized方法,那么在该方法没有执行完成之前或者抛出异常之前,其他线程是无法访问该对象的任何synchronized方法。
    • 被synchronized保护的变量应该是private修饰的。
    • 如果某个synchronized方法被static修饰的,那么当线程访问该方法时候,它锁定并不是对象(实例),而是synchronized方法所以在对象所对应的Class对象,因为Java中无论一个类有多少个对象,这些对象都会对应唯一一个Class对象,因此当线程分别访问一个类的两个对象的两个static synchronized方法时,他们的执行顺序是顺序的,也就是说一个线程先执行方法,执行完毕后另一个线程才开始执行。
    • synchronized方法是一个粗粒度的控制,某一个时刻只能有一个方法执行synchronized方法;sysnchronized块则是一种细粒度的控制方;只会将代码块同步。位于方法内、synchronized块之外的代码是可以被多个线程同时访问的。