Java基础JAVA语言

Java多线程入门不完全指南

2018-01-18  本文已影响274人  leo5592368

Java多线程入门不完全指南

序言

最近在读《把时间当作朋友》,序言就教导我“无论是谁,都是在某一刻意识到时间的珍贵,并且注定会因懂事太晚而多少有些后悔”。想想我,快走出奔三的泥沼,踏入奔四的深渊,越来越意识到时间的弥足珍贵。于是就想着,趁着还有些精力的时候,记录一下所闻、所学、所感。思考良久,记录些什么呢?先记录一下我这拙劣而又不放弃的Java学习之路吧,挖坑一篇"粗而广"的Java多线程介绍压压惊。

基础知识

线程与进程

同步与异步

同步与异步关注的是消息通信机制。

阻塞与非阻塞

阻塞与非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。

并行与并发

多线程与线程安全

线程的状态

5种状态

根据线程的生命周期,可以将线程分为以下5种状态:

  1. NEW(新建):创建了一个线程,尚未启动
  2. RUNNABLE(可运行):线程创建后,其他线程调用了该线程的start()方法,该线程便等待被CPU调度执行。
  3. RUNNING(运行):RUNNABLE状态的线程被CPU调度,获取了CPU时间片,运行run()方法。
  4. BLOCKERD(阻塞):线程无法获取CPU时间片,暂时停止运行的状态。这个状态的线程只有状态转为RUNNABLE时,才有机会被CPU调度执行。阻塞有三种情况:
    • 等待阻塞:如RUNNING状态的线程执行wait()方法。
    • 同步阻塞:如RUNNING状态的线程在获取同步锁时,同步锁被其他线程占用。
    • 其他阻塞:如RUNNING状态的线程执行sleep()方法或其他线程调用join()方法。
  5. DEAD(死亡):线程run()方法执行结束或异常退出,该线程死亡,结束生命周期。

状态转换

线程状态转换图

等待队列和锁池是如何工作的?

Thread类定义的线程状态

  1. NEW(新建):线程创建后未启动。

     /**
      * Thread state for a thread which has not yet started.
      */
    
  2. RUNNABLE(可运行):等待系统资源运行的线程。

     /**
      * Thread state for a runnable thread.  A thread in the runnable
      * state is executing in the Java virtual machine but it may
      * be waiting for other resources from the operating system
      * such as processor.
      */
    
  3. BLOCKED(阻塞):当一个线程要进入synchronized语句块/方法时,如果没有获取到锁,会变成BLOCKED。或者在调用Object.wait()后,被notify()唤醒,再次进入synchronized语句块/方法时,如果没有获取到锁,会变成BLOCKED。进入阻塞状态是被动的。

     /**
      * Thread state for a thread blocked waiting for a monitor lock.
      * A thread in the blocked state is waiting for a monitor lock
      * to enter a synchronized block/method or
      * reenter a synchronized block/method after calling
      * {@link Object#wait() Object.wait}.
      */
    
  4. WAITING(无限等待):等待其它线程执行后,显示唤醒。调用锁对象的wait()方法并未设置时间、其它线程调用join()方法并未设置时间、调用LockSupport.park()方法都会使当前线程进入此状态。进入等待状态是主动的。

     /**
      * Thread state for a waiting thread.
      * A thread is in the waiting state due to calling one of the
      * following methods:
      * <ul>
      *   <li>{@link Object#wait() Object.wait} with no timeout</li>
      *   <li>{@link #join() Thread.join} with no timeout</li>
      *   <li>{@link LockSupport#park() LockSupport.park}</li>
      * </ul>
      *
      * <p>A thread in the waiting state is waiting for another thread to
      * perform a particular action.
      *
      * For example, a thread that has called <tt>Object.wait()</tt>
      * on an object is waiting for another thread to call
      * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
      * that object. A thread that has called <tt>Thread.join()</tt>
      * is waiting for a specified thread to terminate.
      */
    
  5. TIMED_WAITING(限期等待):等待一段时间后被系统唤醒,不需要显示被唤醒。调用Thread.sleep()方法、调用锁对象的wait()方法并设置时间、其它线程调用join()方法并设置时间、调用LockSupport.parkNanos()方法、调用LockSupport.parkUntil()方法都会使线程进入此状态。

     /**
      * Thread state for a waiting thread with a specified waiting time.
      * A thread is in the timed waiting state due to calling one of
      * the following methods with a specified positive waiting time:
      * <ul>
      *   <li>{@link #sleep Thread.sleep}</li>
      *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
      *   <li>{@link #join(long) Thread.join} with timeout</li>
      *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
      *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
      * </ul>
      */
    
  6. TERMINATED(结束):线程run()方法执行结束或异常退出后的线程状态。

     /**
      * Thread state for a terminated thread.
      * The thread has completed execution.
      */
    

VisualVM线程监控

通过JDK自带的VisualVM工具可以监控线程的运行状态,按照下图操作可以抓取线程Dump,监控线程的状态。


visualVM界面.png

VisualVM将线程的状态分为五种:运行、休眠、等待、驻留、监视,与Thread类中的线程状态对应如下:

Thread类 VisualVM
RUNNABLE 运行
TIMED_WAITING (sleeping) 休眠
TIMED_WAITING (on object monitor) WAITING (on object monitor) 等待
TIMED_WAITING (parking) WAITING (parking) 驻留
BLOCKED (on object monitor) 监视

内存原子性、可见性和有序性

Java内存模型

概念

  1. 线程之间通信由Java内存模型控制,内存模型决定了一个线程对共享变量的写入何时对另一个线程可见。
  2. 每个线程都被抽象出一个保存共享变量副本的工作内存,线程对共享变量的操作都在此工作内存中进行。
  3. 某个线程无法直接访问其他线程中的变量,线程之间的通信需要通过主内存来实现。


    内存模型

线程通信过程

  1. 线程A从主内存中拷贝共享变量1到工作内存中的副本,对副本的值进行修改。
  2. 线程A刷新修改后的值到主内存中。
  3. 线程B将主内存中共享变量1拷贝到工作内存中。

并发编程三个特征

Sychronized与Volatile

Java锁机制

Java中的锁

这三种锁是怎么实现的?什么是AQS?什么是CAS?CAS的ABA问题怎么解决?集群环境下如何实现同步?有待后续分晓

Java多线程实现

创建线程的方式

Executor线程池框架

为什么要用线程池?

Executors创建线程池

线程池执行任务

那么线程池的实现原理是什么?有待后续见分晓

上一篇下一篇

猜你喜欢

热点阅读