什么是线程

  • 进程受CPU时间片的轮转调度,进而予人多任务并发的感觉。
  • 线程在更低层次上扩展多任务概念,一个进程通常包含多个线程。
  • 进程各自数据独立,而线程共享数据。
  • 数据独立使进程相互通信变得繁难,共享数据又使线程并发暗藏风险。

创建线程的两种方式:

  • 创建一个任务,受单独线程调度。
    public class Task implements Runnable {
    public void run() {
    // TODO: 具体的执行
    }
    public static void main(String[] args) {
    Runnable runnable = new Task();
    Thread t = new Thread(runnable);
    t.start();
    }
    }
  • 创建一个Thread类的子类,不推荐该方式。
    public class MyThread extends Thread {
    @Override
    public void run() {
    // TODO: 具体的执行任务
    }
    }

中断线程

  • 可以用interrupt方法请求中止线程,线程的中断标志被置位,线程某些情况下应不时检查该标志
    while (!Thread.currentThread().isInterrupted()) {
    // TODO: 接着做
    }
  • 如果线程阻塞(调用sleep或wait),被interrupt的线程会抛出InterruptedException,不可中断的阻塞不会响应interrupt
  • 如果已被interrupt的线程调用sleep,将会复位中断标志并抛出InterruptedException
  • Thread有两个非常类似的方法,interrupted与isInterrupted。interrupted是静态方法,会复位当前线程的中断标志,isInterrupted是实例方法,不改变中断标志

线程状态

线程一共含有6种状态,记于java.lang.Thread.State:

  1. New
  2. Runnable
  3. Blocked
  4. Waiting
  5. Timed waiting
  6. Terminated

线程不会一直保持运行。

抢占式调度系统在分配时间片时赋予线程运行权,时间片用完时剥夺线程运行权。

选择下一线程时会考虑线程的优先级。

Blocked、Waiting、Timed waiting:

  • 当前线程试图获取对象锁而不得时,进入Blocked状态。当其他线程释放该锁,且当前线程持有该锁进入非Blocked状态。
  • 当线程等待java.util.concurrent库中Lock或Condition、调用Object.wait、Thread.join等方法时,进入Waiting状态。此时当前线程在等待另一线程通知线程调度器。
  • 当线程调用Thread.sleep、Object.wait、Thread.join、Lock.tryLock、Condition.await等待时间参数的超期方法,进入Timed waiting状态。
  • 当一个线程被重新激活时,线程调度器会检查其优先级是否比已在运行的线程优先级高,若是,则挑一个线程剥夺其运行权,选择被激活线程运行。

线程退出

  • run方法退出而线程退出
  • 因未捕获异常抛出而线程退出

线程属性

优先级

  • 每个线程都有优先级。
  • 默认情况下,每个线程继承父线程的优先级。
  • 可以调用Thread.setPriority设置线程的优先级
  • JVM的线程优先级高度依赖于系统,Java线程的优先级被映射到宿主平台的优先级上。
  • Windows上有7个优先级,Java线程优先级会出现多对一的情况。
  • Linux上线程不具有优先级。

守护线程

  • 线程启动前调用Thread.setDaemon(true)将线程转换为守护线程
  • 当只剩下守护线程时,JVM退出

Unchecked Exception处理器

  • 调用Thread.setUncaughtExceptionHandler为线程安装异常处理器
  • 调用静态Thread.setDefaultUncaughtExceptionHandler为所有线程安装默认异常处理器
  • 如果不为线程安装异常处理器,默认处理器为该线程的ThreadGroup对象
  • ThreadGroup的uncaughtException的处理逻辑如下:
    • 父ThreadGroup
    • DefaultUncaughtExceptionHandler
    • Throwable不是ThreadDeath实例,线程名字以及Throwable的栈信息输出到System.err
  • 使用Unchecked Exception处理器目的在于健壮线程异常退出的记录,如需恢复当前任务只能新建线程重新执行

线程同步

java.util.concurrent.locks.ReentrantLock

  • 示例代码
    private Lock lock = new ReentrantLock();
    
    public void doSomething() {
    lock.lock();
    try {
    // do something
    } finally {
    lock.unlock();
    }
    }
  • ReentrantLock 可重入,锁内部有计数机制
  • 构造器ReentrantLock(boolean fair)构建公平策略锁,以牺牲性能的代价偏爱等待时间最长的线程。无法保证线程调度器的绝对公平。

java.util.concurrent.locks.Condition

  • 一个锁可以含有一个或多个条件对象
  • 调用java.util.concurrent.locks.Lock#newCondition获得一个条件对象
  • 线程在持有锁的情况下调用java.util.concurrent.locks.Condition#await()放弃锁并阻塞在Condition的等待集上
  • 另一线程java.util.concurrent.locks.Condition#signalAll激活因条件对象阻塞的线程,这些线程从等待集中移出,再次接受线程调度器的调度,试图重入锁对象。一旦获得锁对象,将从await调用地方返回并继续执行
  • 示例代码
    while(!(ok to proceed))
    condition.await();

synchronized

  • 每个JAVA对象都有一个内部锁
  • 对象内部锁只有一个Condition
  • 对象内部锁的wait与notifyAll,等价于Condition的await与signalAll
  • synchronized方法锁对象
  • synchronized静态方法锁对象的类

Volatile

  • 不同线程访问同一内存地址可能获得不同的值,因为寄存器或本地缓冲区的存在
  • 编译器可以改变指令执行的顺序而不改变代码的语义
  • 使用锁不必担心数据访问不一致,锁保护的临界区不能重排序指令,必要时刷新本地缓存
  • 将域声明为volatile保证数据访问一致性,但不保证数据修改的原子性

final

  • final修饰的域保证多线程下数据访问一致性

Atomic

  • java.util.concurrent.atomic下提供了诸如AtomicInteger、AtomicReference等原子类
  • Atomic既保证数据访问一致性,同时保证了数据修改的原子性

ThreadLocal

  • 每个线程拿到的变量值都是特属于自己的副本,故没有同步的代价
  • java.util.Random是线程安全的,为提高性能JAVA 7引入了java.util.concurrent.ThreadLocalRandom
  • java.text.SimpleDateFormat是非线程安全的,解决该问题为每一个线程构造一个实例,示例代码如下
    public static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
    return new SimpleDateFormat("yyyy-MM-dd");
    }
    };

Lock's wait and interrupt

  • java.util.concurrent.locks.Lock#lock不能被中断,如果线程在等待获得锁时被中断,被中断线程在获得锁之前一直处于阻塞状态
  • java.util.concurrent.locks.Lock#tryLock(long, java.util.concurrent.TimeUnit)可以被中断,中断将抛出InterruptedException
  • java.util.concurrent.locks.Condition#await(long, java.util.concurrent.TimeUnit)与tryLock类似

write/read Lock

  • java.util.concurrent.locks.ReentrantReadWriteLock读并发,写互斥
  • readLock获取读锁,多个读操作可重入,排斥写锁。
  • writeLock获取写锁,排斥其他所有锁。

阻塞队列

队列方法

  • add 添加一个元素,如果队列满则抛错
  • element 返回队列的头元素,如果队列空则抛错
  • offer 添加一个元素返回true,如果队列满则返回false
  • peek 返回队列头元素,如果队列空,返回null
  • poll 移出并返回队列头元素,如果队列空,返回null
  • put 添加一个元素,如果队列满则阻塞
  • remove 移出并返回队列头元素,如果空则抛错
  • take 移出并返回队列头元素,如果空则阻塞

七种队列

  • ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
  • LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
  • PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
  • DelayQueue:一个使用优先级队列实现的无界阻塞队列。
  • SynchronousQueue:一个不存储元素的阻塞队列。
  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
  • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

参考资料

JAVA 技术手册 卷1 第十四章『多线程』 读书摘要的更多相关文章

  1. 《Java并发编程实战》第十四章 构建自己定义的同步工具 读书笔记

    一.状态依赖性的管理 有界缓存实现的基类 @ ThreadSafe public abstract class BaseBoundedBuffer<E> { @GuardeBy( &quo ...

  2. 《Java并发编程实战》第十四章 构建自己的同步工具定义 札记

    一.状态依赖性的管理 有界缓存实现的基类 @ ThreadSafe public abstract class BaseBoundedBuffer<E> { @GuardeBy( &quo ...

  3. java并发编程实战:第十四章----构建自定义的同步工具

    一.状态依赖性管理 对于单线程程序,某个条件为假,那么这个条件将永远无法成真 在并发程序中,基于状态的条件可能会由于其他线程的操作而改变 可阻塞的状态依赖操作的结构 acquire lock on o ...

  4. 《Java编程思想》笔记 第十四章 类型信息

    1.RTTI:在运行时识别一个对象类型 JAVA在运行时 有时要 识别对象和类的信息这个机制叫RTTI.Java提供了两种机制去做这件事.传统的RTTI 和 反射. 传统的RTTI  假定编译时就已经 ...

  5. 《Python 学习手册4th》 第十四章 迭代器和解析

    ''' 时间: 9月5日 - 9月30日 要求: 1. 书本内容总结归纳,整理在博客园笔记上传 2. 完成所有课后习题 注:“#” 后加的是备注内容 (每天看42页内容,可以保证月底看完此书) “重点 ...

  6. 《Java并发编程实战》第十二章 测试并发程序 读书笔记

    并发测试分为两类:安全性测试(无论错误的行为不会发生)而活性测试(会发生). 安全測试 - 通常採用測试不变性条件的形式,即推断某个类的行为是否与其它规范保持一致. 活跃性測试 - 包含进展測试和无进 ...

  7. “全栈2019”Java多线程第三十四章:超时自动唤醒被等待的线程

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  8. “全栈2019”Java多线程第二十四章:等待唤醒机制详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  9. “全栈2019”Java多线程第十四章:线程与堆栈详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

随机推荐

  1. Ruby的require相关知识

    1. 在调用require xxx之前,需要确定xxx这个gem已经安装过了(使用gem install xxx,安装位置可以使用gem env列出),或者xxx是Ruby内置的标准函数库(StdLi ...

  2. [转载]Linux 线程实现机制分析

    本文转自http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 支持原创.尊重原创,分享知识! 自从多线程编程的概念出现在 Linux ...

  3. Ant :Property

     Property Ant 内置的Property 系统属性 Ant附加的属性 自定义Property Ant :Property properties是由key-value组成的集合,就是Java中 ...

  4. chrome 浏览器的预提取资源机制导致的一个请求发送两次的问题以及ClientAbortException异常

    调查一个 pdf 打印报错: ExceptionConverter: org.apache.catalina.connector.ClientAbortException: java.net.Sock ...

  5. PHP笔记(PHP初级篇)

    学习完HTML和CSS后,终于要开始学习PHP啦!前面的铺垫只为后路的畅顺! PHP环境搭建: 企业中常用到的环境是:Linux+Apache+MySQL+PHP 学习环境是:Windows+Apac ...

  6. Godaddy SSL 安装及Tomcat 7配置

    基础环境:Centos 7.X 1. 安装tomcat 与java 环境: 2.使用jre 程序的keytool 生成密钥,java 我使用解压版本并运行目录在/usr/java, 生成tomcat. ...

  7. php函数 ceil floor round和 intval

    1.ceil 如果有小数部分 则进一位 < ?php echo ceil(4.3); echo ceil(9.999); ?> 2.floor 舍小取整 < ? php echo f ...

  8. Android欢迎界面

    欢迎界面,最典型的表现: 1.是整个应用的启动界面: 2.没有标题栏: 3.几秒之后才进入主界面. 所以实现上面3点,一个最基本的欢迎界面就做出来了. 首先,新建一个Activity,命名为Splas ...

  9. Comparison of SQL Server Compact, SQLite, SQL Server Express and LocalDB

    Information about LocalDB comes from here and SQL Server 2014 Books Online. LocalDB is the full SQL ...

  10. CSS控制TD内的文本超出指定宽度后不换行而用省略号代替

    <style type="text/css"> .lineOverflow { width: 100px; border:#000 solid 1px; text-ov ...