什么是线程

  • 进程受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: 接着做
    }
  • 如果线程阻塞(调用sleepwait),被interrupt的线程会抛出InterruptedException,不可中断的阻塞不会响应interrupt
  • 如果已被interrupt的线程调用sleep,将会复位中断标志并抛出InterruptedException
  • Thread有两个非常类似的方法,interruptedisInterruptedinterrupted是静态方法,会复位当前线程的中断标志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库中LockCondition、调用Object.waitThread.join等方法时,进入Waiting状态。此时当前线程在等待另一线程通知线程调度器。
  • 当线程调用Thread.sleepObject.waitThread.joinLock.tryLockCondition.await等待时间参数的超期方法,进入Timed waiting状态。
  • 当一个线程被重新激活时,线程调度器会检查其优先级是否比已在运行的线程优先级高,若是,则挑一个线程剥夺其运行权,选择被激活线程运行。

线程退出

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

线程属性

优先级

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

守护线程

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

Unchecked Exception处理器

  • 调用Thread.setUncaughtExceptionHandler为线程安装异常处理器
  • 调用静态Thread.setDefaultUncaughtExceptionHandler为所有线程安装默认异常处理器
  • 如果不为线程安装异常处理器,默认处理器为该线程的ThreadGroup对象
  • ThreadGroupuncaughtException的处理逻辑如下:
    • 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
  • 对象内部锁的waitnotifyAll,等价于ConditionawaitsignalAll
  • synchronized方法锁对象
  • synchronized静态方法锁对象的类

Volatile

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

final

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

Atomic

  • java.util.concurrent.atomic下提供了诸如AtomicIntegerAtomicReference等原子类
  • 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. iOS开发之功能模块--高仿Boss直聘的IM界面交互功能

    本人公司项目属于社交类,高仿Boss直聘早期的版本,现在Boss直聘界面风格,交互风格都不如Boss直聘以前版本的好看. 本人通过iPhone模拟器和本人真机对聊,将完成的交互功能通过Mac截屏模拟器 ...

  2. 第一课 ionic 日志输出

    写程序的首要问题就是要打印日志,因为只有将日志输出才能真正了解程序的运行状态. 日志输出有两种方式 1.console输出 console.log("测试一下") console. ...

  3. [转]浅谈CSRF攻击方式

    在CSDN中看到对CSRF攻击的原理及防护文章,讲解浅显易懂,特转之: 来源:http://blog.csdn.net/fationyyk/article/details/50833620 一.CSR ...

  4. Linux SendMail服务启动慢总结

    在 CentOS release 6.6 上启动sendmail服务时发现服务启动过程非常慢,基本上要耗费3分多钟.有点纳闷:什么原因导致sendmail启动这么慢?搜索了这方面的一些资料,结合自己的 ...

  5. [原创]纯CSS3打造的3D翻页翻转特效

    刚接触CSS3动画,心血来潮实现了一个心目中自己设计的翻页效果的3D动画,页面纯CSS3,目前只能在Chrome中玩,理论上可以支持Safari. 1. 新建HTML,代码如下(数据和翻页后的数据都是 ...

  6. Mac安装Windows 10的简明教程

    每次在Mac上安装Windows都是一件非常痛苦的事情,曾经为了装Win8把整台Mac的硬盘数据都弄丢了,最后通过龟速系统恢复模式恢复了MacOSX(50M电信光纤下载了3天才把系统下载完),相信和我 ...

  7. java设计模式之原型模式

    原型模式概念 该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.java中复制通过clone()实现的.clone中涉及深.浅复制.深.浅复制的概念如下: ⑴浅复制 ...

  8. 【原】使用VirtIE6代替IE6

    做前端开发难免要使用IE6,相信很多朋友知道win7上是不支持安装IE6的,通常会使用IETester,要么在win7中安装虚拟机,在虚拟机中安装IE6. 分析下这2种方式: IETester:并不是 ...

  9. Struts2 Ajax校验

    Ajax(Asynchronous javascript and xml):异步刷新技术 技术组成:  CSS + xml +JavaScript +DOM Ajax核心对象: XMLHttpRequ ...

  10. idea快捷键(自用)

    idea快捷键(自用) 1.比如输入eclipse下面的main,sysout等,在idea里面同样可以实现,如下: sysout(sout 按tab),main(psvm按tab),具体可按照ctr ...