1、参考资料(多线程系列)

1、:Java多线程系列目录

1.1、基础篇

01. Java多线程系列--“基础篇”01之 基本概念

02. Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式

03. Java多线程系列--“基础篇”03之 Thread中start()和run()的区别

04. Java多线程系列--“基础篇”04之 synchronized关键字

05. Java多线程系列--“基础篇”05之 线程等待与唤醒

06. Java多线程系列--“基础篇”06之 线程让步

07. Java多线程系列--“基础篇”07之 线程休眠

08. Java多线程系列--“基础篇”08之 join()

09. Java多线程系列--“基础篇”09之 interrupt()和线程终止方式

10. Java多线程系列--“基础篇”10之 线程优先级和守护线程

11. Java多线程系列--“基础篇”11之 生产消费者问题

1.2、JUC原子类

12. Java多线程系列--“JUC原子类”01之 框架

13. Java多线程系列--“JUC原子类”02之 AtomicLong原子类

14. Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

15. Java多线程系列--“JUC原子类”04之 AtomicReference原子类

16. Java多线程系列--“JUC原子类”05之 AtomicLongFieldUpdater原子类

 1.3、JUC锁

17. Java多线程系列--“JUC锁”01之 框架

18. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

19. Java多线程系列--“JUC锁”03之 公平锁(一)

20. Java多线程系列--“JUC锁”04之 公平锁(二)

21. Java多线程系列--“JUC锁”05之 非公平锁

22. Java多线程系列--“JUC锁”06之 Condition条件

23. Java多线程系列--“JUC锁”07之 LockSupport

24. Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock

25. Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例

26. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

27. Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

1.4、JUC集合

28. Java多线程系列--“JUC集合”01之 框架

29. Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList

30. Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet

31. Java多线程系列--“JUC集合”04之 ConcurrentHashMap

32. Java多线程系列--“JUC集合”05之 ConcurrentSkipListMap

33. Java多线程系列--“JUC集合”06之 ConcurrentSkipListSet

34. Java多线程系列--“JUC集合”07之 ArrayBlockingQueue

35. Java多线程系列--“JUC集合”08之 LinkedBlockingQueue

36. Java多线程系列--“JUC集合”09之 LinkedBlockingDeque

37. Java多线程系列--“JUC集合”10之 ConcurrentLinkedQueue

1.5、JUC线程池

38. Java多线程系列--“JUC线程池”01之 线程池架构

39. Java多线程系列--“JUC线程池”02之 线程池原理(一)

40. Java多线程系列--“JUC线程池”03之 线程池原理(二)

41. Java多线程系列--“JUC线程池”04之 线程池原理(三)

42. Java多线程系列--“JUC线程池”05之 线程池原理(四)

43. Java多线程系列--“JUC线程池”06之 Callable和Future

2、简要总结

  多线程是Java中不可避免的一个重要主体。从本章开始,我们将展开对多线程的学习。接下来的内容,是对“JDK中新增JUC包”之前的Java多线程内容的讲解,涉及到的内容包括,Object类中的wait(), notify()等接口;Thread类中的接口;synchronized关键字。

注:JUC包是指,Java.util.concurrent包,它是由Java大师Doug Lea完成并在JDK1.5版本添加到Java中的。

2.1、线程状态

说明
线程共包括以下5种状态。
1. 新建状态(New)         : 线程对象被创建但还没有调用start方法时,处于新建状态。例如,Thread thread = new Thread()。
2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
3. 运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
4. 阻塞状态(Blocked)  : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
    (02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
    (03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5. 死亡状态(Dead)    : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程的5种状态涉及到的内容包括Object类, Thread和synchronized关键字。这些内容我们会在后面的章节中逐个进行学习。
Object类,定义了wait(), notify(), notifyAll()等休眠/唤醒函数。
Thread类,定义了一些列的线程操作函数。例如,sleep()休眠函数, interrupt()中断函数, getName()获取线程名称等。

Java线程状态:

注:其实Java在Thread类中定义了线程的状态(enum State),共有六种:NEW、RUNNABLE、TERMINATED、BLOCKED、WAITING、TIMED_WAITING。

  • RUNNABLE包括上述的Runnable和Running。
  • WAITING表示无线等待,需要被唤醒,如执行wait()、join()方法
  • TIMED_WAITING表示有限等待,在一定时间后自动唤醒,如执行wait(long timems)、join(long timems)、sleep(long timems)方法
  • BLOCKED表示阻塞,线程等待进入同步区时进入此状态

2.2、线程状态转换方法

详见:Java线程状态及 join、sleep、wait、notify、yield等的区别

2.3、同步互斥

同步:在多个线程并发访问共享数据时,保证数据在同一时刻只被一个(或一些,使用信号量的时候)线程使用。可以分为阻塞同步(如互斥)和非阻塞同步(需要硬件指令集的发展以保障“操作和冲突检测”的原子性,CAS操作等)。

互斥:实现同步的一种手段,属于阻塞同步。临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)是主要的互斥实现方式

互斥是因,同步是果;互斥是方法,同步是目的。

2.4、线程协作

待...

2.5、线程竞争

多线程共享内存(竞争访问同一资源)带来的问题:(参考资料:http://mp.weixin.qq.com/s/DC6JlRo7LEx4rRsz9U_Xpw

1、竞态条件(race condition):当多个线程访问和操作同一个对象时,最终执行结果与执行时序有关,可能正确也可能不正确

解决:

  • 使用synchronized关键字(相关:synchronized关键字
  • 使用显式锁
  • 使用原子变量(计数、序号等场景)或原子更新(被更新的变量需被volatile修饰)
     // 2、原子变量
    // 对于count++这种操作来说,使用synchronzied成本太高了,需要先获取锁,最后还要释放锁,获取不到锁的情况下还要等待,还会有线程的上下文切换,这些都需要成本。
    //
    // 对于这种情况,完全可以使用原子变量代替,Java并发包中的基本原子变量类型有:
    // AtomicBoolean:原子Boolean类型
    // AtomicInteger:原子Integer类型
    // AtomicLong:原子Long类型
    // AtomicReference:原子引用类型
    class AtomicIntegerDemo {
    private static AtomicInteger counter = new AtomicInteger(0); static class Visitor extends Thread {
    @Override
    public void run() {
    for (int i = 0; i < 100; i++) {
    counter.incrementAndGet();
    Thread.yield();
    }
    }
    } public static void main(String[] args) throws InterruptedException {
    int num = 100;
    Thread[] threads = new Thread[num];
    for (int i = 0; i < num; i++) {
    threads[i] = new Visitor();
    threads[i].start();
    }
    for (int i = 0; i < num; i++) {
    threads[i].join();
    }
    System.out.println(counter.get());
    }
    } // 原子更新
    class FieldUpdaterDemo {
    static class DemoObject {// 类DemoObject中有两个成员num和ref,声明为volatile,但不是原子变量,不过DemoObject对外提供了原子更新方法compareAndSet,它是使用字段对应的FieldUpdater实现的,FieldUpdater是一个静态成员,通过newUpdater工厂方法得到,newUpdater需要的参数有类型、字段名、对于引用类型,还需要引用的具体类型。
    private volatile int num;
    private volatile Object ref; private static final AtomicIntegerFieldUpdater<DemoObject> numUpdater = AtomicIntegerFieldUpdater
    .newUpdater(DemoObject.class, "num");
    private static final AtomicReferenceFieldUpdater<DemoObject, Object> refUpdater = AtomicReferenceFieldUpdater
    .newUpdater(DemoObject.class, Object.class, "ref"); public boolean compareAndSetNum(int expect, int update) {
    return numUpdater.compareAndSet(this, expect, update);
    } public int getNum() {
    return num;
    } public Object compareAndSetRef(Object expect, Object update) {
    return refUpdater.compareAndSet(this, expect, update);
    } public Object getRef() {
    return ref;
    }
    } public static void main(String[] args) {
    DemoObject obj = new DemoObject();
    obj.compareAndSetNum(0, 100);
    obj.compareAndSetRef(null, new String("hello"));
    System.out.println(obj.getNum());
    System.out.println(obj.getRef());
    }
    }

2、内存可见性:多个线程可以共享访问和操作相同的变量,但一个线程对一个共享变量的修改,另一个线程不一定马上就能看到,甚至永远也看不到

解决:

  • 使用volatile关键字(相关:volatile关键字
  • 使用synchronized关键字同步
  • 使用显式锁同步

2.6、 对象的线程安全

1、线程安全:(Brian Goetz《Java Concurrency In Practice》)当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步或在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那此对象是线程安全的。

此定义要求线程安全的代码都必须具备一个特征:代码本身封装了所有必要的正确性保障手段(如互斥同步等),令调用者无须关心多线程的问题,更无须采取任何措施保证多线程的正确调用。此并不易做到,在大多数场景中,会将此定义弱化些,若把“调用这个对象的行为”限定为“单次调用”,此定义的其他描述也能成立,则称之是线程安全的了。

2、保证线程安全的思路

  1. 锁,使用synchronized或ReentrantLock(悲观策略),参看理解synchronized
  2. 原子操作,循环CAS(乐观策略),参看原子变量和CAS
  3. 写时拷贝,如CopyOnWriteArrayList,适用于元素个数不多,绝大部分访问都是读,且有大量并发线程要求读,只有个别线程进行写,且只是偶尔写的场合。(参看写时拷贝的List和Set

最新文章

  1. sublime快捷键
  2. Python Day5
  3. 【转载】Visaul Studio 常用快捷键的动画演示
  4. jenkins和docker 在docker里运行jenkins
  5. Swift控制流
  6. Java Hour 15 以写小说的心态
  7. MongoDB 一对多关系建模
  8. jfinal对象封装Record原理
  9. jq向上无缝滚动
  10. Phoenix二级索引(Secondary Indexing)的使用
  11. enode框架step by step之saga的思想与实现
  12. 学习笔记TF061:分布式TensorFlow,分布式原理、最佳实践
  13. Markdown基础语法笔记
  14. 前端(二)之 CSS
  15. H5 67-清除浮动方式三
  16. 大杂烩 -- equals、hashCode联系与区别
  17. JS 使用html2canvas实现截图功能的问题记录和解决方案
  18. MySQL 5.7的原生JSON数据类型使用
  19. ZOJ 3329 One Person Game (经典概率dp+有环方程求解)
  20. HPU :字符串的统计

热门文章

  1. Linux下解决用户不能执行sudo的方法
  2. Gson解析json数据
  3. 用 Fabric 实现自动化部署
  4. iOS开发中的错误整理,Changing the delegate of a tab bar managed by a tab bar controller is not allowed
  5. 81B
  6. java-二维码编写zxing
  7. Android中图像变换Matrix的原理、代码验证和应用(三)
  8. Web前端性能优化教程06:减少DNS查找、避免重定向
  9. 【转】wait,notify,notifyAll,join,yield,sleep的区别和联系
  10. 随机验证码生成(python实现)