目录

一、线程和并发

1.1 线程介绍

1.2 线程安全,实现线程安全的主要方法

1.3 线程的优点和缺点?

1.4 并发级别

二、Java 内存模型

2.1 什么是 Java 内存模型,以及Java内存模型的作用?

2.2 Happen Before 原则

三、锁机制

3.1 内置锁

3.2 可重入锁

3.3 锁优化

3.4 锁优化

3.5 死锁的四个条件和死锁避免

3.6 synchronized 和 Lock 锁的区别?

3.7 sleep() 和 wait() 方法的区别?

四、并发容器类

4.1 同步容器类

4.2 同步并发类

4.3 同步工具类

4.4 Executor

五、并发设计模式

5.1 Future 模式

5.2 生产者消费者模式

5.3 单例模式

5.4 CopyOnWrite(String)


一、线程和并发

1.1 线程介绍

1)任务调度和分配的基本单位,一个进程内有多个线程,共享进程中的资源,减少进程切换的时空开销,提升并发效率。

2)线程的五个状态:NEW、RUNNABLE、BLOCKED、WAIT/TIMED_WAITING、TERMINATED。

3)线程同步的方式:

通过 Object 的 wait() 和 notify();(用在sychronized锁中)
通过 Condition 的 awiat() 和 signal();(用在Reentrant Lock锁中)
通过阻塞队列;
通过线程池的Callback回调;
通过同步辅助类CountDownLatch;
通过同步辅助类CyclicBarrier;
信号量 Semphare;

1.2 线程安全,实现线程安全的主要方法

多个线程访问某个类,始终保持正确的行为。

1、互斥同步(悲观锁);

2、非互斥同步(乐观锁)。

1.3 线程的优点和缺点?

优点:1)充分利用多核 CPU 的资源,提升系统效率;

2)建模简单;

3)异步事件的简单处理。

缺点:1)安全性问题(程序执行顺序);

2)死锁;

3)资源消耗过高、吞吐率过低、响应不灵敏等。

1.4 并发级别

1)阻塞:sychronized关键字;

2)无饥饿:公平队列;

3)无障碍:一致性标记;

4)无锁:CAS;

5)无等待:CopyOnWriteArrayList;

二、Java 内存模型

2.1 什么是 Java 内存模型,以及Java内存模型的作用?

Java 内存模型定义各个变量的访问规则,由 violate、final、sychronized 关键字实现原子性、可见性、有序性,以及 happen before 原则组成,happen before 原则:程序顺序规则、管程规则、violate规则、线程start()规则、线程join()规则、传递性规则。

2.2 Happen Before 原则

1、程序顺序规则:

2、管程规则:

3、violate规则:

4、线程start()规则:

5、线程join()规则:

6、传递性规则:

三、锁机制

3.1 内置锁:sychronized

JVM 基于 Monitor 对象,利用 monitorenter 和 monitorexit 这两个字节码指令实现。

3.2 可重入锁:ReetrantLock

ReetrantLock 底层实现原理AbstractQueuedSynchronizer(抽象队列同步器):核心数据结构:双向链表 + state(锁状态)、底层操作:CAS。

创建 ReentrantLock 的对象的时候 ,其实是创建了一个 NonfairSync() 对象,NonfairSync类是静态内部类,他继承了Sync,Sync继承了AbstractQueuedSynchronizer。

    /*** Creates an instance of {@code ReentrantLock}.* This is equivalent to using {@code ReentrantLock(false)}.*/public ReentrantLock() {sync = new NonfairSync();}

3.3 锁

重量级锁:Synchronized 的重量级锁是通过对象内部的一个叫做监视器锁(monitor)来实现的,监视器锁本质又是依赖于底层操作系统的Mutex Lock(互斥锁)来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间。

1、自旋锁:

2、轻量级锁:

3、所偏向:

4、锁消除:是指虚拟机即时编译器(JIT)在运行时,对一些代码上要求同步,但是检测到不可能发生数据竞争的锁进行消除。

5、锁粗化:

3.4 锁优化

1、缩小锁的范围;

2、减小锁的粒度:即使用对个对象内置锁。

3.5 死锁的四个条件和死锁避免

因为申请资源而互相等待其他线程释放资源,

死锁的四个必要条件:1)互斥;2)占有并等待;3)不剥夺;4)循环等待。

破坏死锁的四个必要条件之一,以及银行家算法。

3.6 synchronized 和 Lock 锁的区别?

1、synchronized 适合线程竞争不激烈的时候;Lock 适合线程竞争激烈的时候。

2、Lock 是可中断的,可设置为公平锁,申请限时等待;

3、synchronized 是对象的内置锁;Lock 是 ReetrantLock 类可重入锁;

4、synchronized 可用来修饰方法和代码块,托管给JVM执行;Lock 需要通过代码实现,一般在 try/catch、finally 代码块中手动编写和释放;

3.7 sleep() 和 wait() 方法的区别?

1、sleep()是Thread类的方法,用于控制自身的流程;wait() 是 Object() 类的方法用于线程同步;

2、sleep()不释放锁;wait()释放锁;

3、sleep()可以在任何地方;wait()只能在 sychronized 修饰的方法和代码块中。

四、并发容器类

4.1 同步容器类

1)Voctor;

2)HashTable。

4.2 同步并发类

1) 点击蓝色字体,跳转到详细介绍界面,ConcurrentHashMap;

2)CopyOnWriteArrayList;

写时复制, 在往集合中添加数据的时候,先拷贝存储的数组,然后添加元素到拷贝好的数组中,然后用现在的数组去替换成员变量的数组(就是get等读取操作读取的数组)。多读取,少添加。

3)ReentrantReadWriteLock:每次只能有一个写线程,但是可以有多个线程并发地读数据。

/*** 基于读写锁和 CountDown 闭锁实现读写锁和 Lock 锁的比较* @author TSjia**/public class ReadWriteLockDemo {private static Lock lock = new ReentrantLock();private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();private static Lock readLock = readWriteLock.readLock();private static Lock writeLock = readWriteLock.writeLock();public static CountDownLatch end = new CountDownLatch(20);private int value;public Object handleRead(Lock lock) throws InterruptedException {try {lock.lock();Thread.sleep(1000);return value;} catch (Exception e) {e.printStackTrace();}finally {end.countDown();lock.unlock();}return 0;}public void handleWrite(Lock lock, int index) throws InterruptedException {try {lock.lock();Thread.sleep(1000);value = index;} catch (Exception e) {e.printStackTrace();}finally {end.countDown();lock.unlock();}}public static void main(String[] args) throws InterruptedException {final ReadWriteLockDemo demo = new ReadWriteLockDemo();Runnable readRunnable = new Runnable() {@Overridepublic void run() {try {demo.handleRead(readLock);// demo.handleRead(lock);} catch (Exception e) {e.printStackTrace();}}};Runnable writeRunnable = new Runnable() {@Overridepublic void run() {try {demo.handleWrite(writeLock, new Random().nextInt());// demo.handleWrite(lock, new Random().nextInt());} catch (Exception e) {e.printStackTrace();}}};long date = System.currentTimeMillis();for(int i=0; i<18; i++) {new Thread(readRunnable).start();}for(int i=18; i<20; i++) {new Thread(writeRunnable).start();new Thread(writeRunnable).start();}end.await();System.out.println("耗费时间:" + (System.currentTimeMillis()-date));}
}

4)阻塞队列和生产者和消费者模型

有界缓冲区(bounded-buffer)问题,阻塞队列 ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue(无界队列)。

PriorityBlockingQueue是一个无界队列,它没有限制,在内存允许的情况下可以无限添加元素;它又是具有优先级的队列,是通过构造函数传入的对象来判断,传入的对象必须实现comparable接口。

/*** 队列 + sychronized + wait()/notifyAll()实现生产者和消费者* @author TSjia**/public class ProduceAndConsumerDemo {public static Object lock = new Object();static class Produce implements Runnable {Queue<Integer> queue = null;public Produce(Queue<Integer> queue) {this.queue = queue;}@Overridepublic void run() {try {synchronized (lock) {while(queue.size() == 5) {lock.wait();}Integer i = new Random().nextInt(100);System.out.println("生产者--生产:" + i);queue.offer(i);lock.notifyAll();}} catch (InterruptedException e) {e.printStackTrace();}}}static class Consumer implements Runnable {Queue<Integer> queue = null;public Consumer(Queue<Integer> queue) {this.queue = queue;}@Overridepublic void run() {try {synchronized (lock) {while(queue.size() == 0) {lock.wait();}System.out.println("消费者--取队列首元素:" + queue.poll());lock.notifyAll();}                        } catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {Queue<Integer> queue = new LinkedList<Integer>();Produce produce = new Produce(queue);       Consumer consumer = new Consumer(queue);for(int i=0; i<100; i++) {Thread t1 = new Thread(produce);t1.start();Thread t2 = new Thread(consumer);t2.start();}}
}

4.3 同步工具类

1)闭锁:CountDownLatch;

用于控制主线程等待其他线程执行结束,再继续执行。

public class CountDownLatchDemo2 {public static void main(String[] args) throws InterruptedException {CountDownLatchDemo2 bisuo = new CountDownLatchDemo2();long threadtime = bisuo.timetasks(10);double ans = (double)threadtime / 1000000000;System.out.println("Thread time:" +ans + "s");}public long timetasks(int nThreads) throws InterruptedException {final CountDownLatch startGate = new CountDownLatch(1);final CountDownLatch endGate = new CountDownLatch(nThreads);for (int i=0; i< nThreads; i++){Thread t = new Thread(){public void run(){try{startGate.await(); //wait the startGate count down to zero, then run.try{Thread.sleep(1000);System.out.println("Thread Id: " + this.getId());} finally {endGate.countDown();}} catch (InterruptedException ignored){ }}};t.start();}long start = System.nanoTime();  //单位纳秒startGate.countDown();endGate.await();                 //wait the endGate count down to zero, then run.long end = System.nanoTime();return end - start;}
}

2)Future;

核心思想时异步调用,当调用一个耗时方法时,后台运行该方法,主线程继续处理其他任务,再获得耗时方法的结果。

// Callable 具体实现
public class TrueData implements Callable<String>{private String queryStr;public TrueData(String queryStr) {this.queryStr = queryStr;}@Overridepublic String call() throws Exception {String result = "";if(queryStr.equals("诸葛亮")) {try {System.out.println("诸葛亮还没睡醒,请等待。。。");Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();}result = "诸葛亮刚刚睡醒!";}elseresult = "我不是诸葛亮,我是他的弟弟诸葛均";return result;}
}
// FutureMain 函数
public class FutureMain {public static void main(String[] args) throws InterruptedException, ExecutionException{// submit提交一个实现 Callable 接口的任务,并且返回封装了异步计算结果的Future。ExecutorService executor = Executors.newFixedThreadPool(1);Future<String> future = executor.submit(new TrueData("诸葛亮"));System.out.println("到达卧龙岗");System.out.println("三顾茅庐 :" + future.get());try {Thread.sleep(3000);} catch (Exception e) {e.printStackTrace();}System.out.println("三顾茅庐 :" + future.get());executor.shutdown();}
}

3)信号量:Semaphore

指定多个线程同时访问同一个资源。

public class SemaphoreDemo {public static void main(String[] args) {// 只能5个线程同时访问  final Semaphore semp = new Semaphore(5);for (int index = 0; index < 20; index++) {final int NO = index;new Thread() {public void run() {try {semp.acquire();  // 获取许可  System.out.println("Accessing: " + NO);Thread.sleep(1000);  // 模拟实际业务逻辑semp.release();  // 访问完后,释放  } catch (InterruptedException e) {}}}.start();}}
} 

4)栅栏:CyclicBarrier

实现多个线程相互等待,直到所有线程都结束之后,再运行后续程序。

class CyclicBarrierWorker implements Runnable {private int id;private CyclicBarrier barrier;public CyclicBarrierWorker(int id, final CyclicBarrier barrier) {this.id = id;this.barrier = barrier;}@Overridepublic void run() {try {System.out.println(id + " th people wait");barrier.await(); // 大家等待最后一个线程到达} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}}public class TestCyclicBarrier {public static void main(String[] args) {int num = 10;CyclicBarrier barrier = new CyclicBarrier(num, new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("go on together!");}});for (int i = 1; i <= num; i++) {new Thread(new CyclicBarrierWorker(i, barrier)).start();}}
}

4.4 Executor

1)继承关系

Executor的UML图

2)四种常见的线程池:

CachedThreadPool:可缓存的线程池;

SecudleThreadPool:周期性执行任务的线程池;

SingleThreadPool:只有一条线程来执行任务;

FixedThreadPool:定长的线程池。

3)ThreadPoolExecutor 类构造函数

public ThreadPoolExecutor(int corePoolSize,  int maximumPoolSize,  long keepAliveTime,  TimeUnit unit,  BlockingQueue<Runnable> workQueue,  ThreadFactory threadFactory,  RejectedExecutionHandler handler)

五、并发设计模式

5.1 Future 模式(见4.3- 2))

5.2 生产者消费者模式(见4.2- 4))

5.3 单例模式

5.4 CopyOnWrite(比如:String)

Java学习路线之并发编程(五)相关推荐

  1. 【Java学习】JUC并发编程

    目录 1.JUC是什么 1.1 JUC简介 1.2 线程和进程概念 1.2.1 进程和线程 1.3 线程的状态 1.3.1 线程状态枚举类 1.3.2 wait和sleep的区别 1.3.3 使用范围 ...

  2. JAVA学习笔记 -- JUC并发编程

    1 进程.线程 进程就是用来加载指令.管理内存.管理IO.当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程.进程可以被视为程序的一个实例. 线程,一个线程就是一个指令流,将指令流 ...

  3. JAVA学习笔记(并发编程-叁)- 线程安全性

    文章目录 线程安全性-原子性 原子性-Atomic包 AtomicXXX: CAS, Unsafe.compareAndSwapInt AtomicLong LongAdder AtomicRefer ...

  4. 阿里云Java学习路线 - Java编程入门 笔记

    学习链接 目录 学习链接 第一章 Java语言介绍 1.Java发展简介 2.Java语言特点 3.Java可移植性 第二章 搭建Java开发环境 1.JDK简介 2.安装完成后配置JDK环境 第三章 ...

  5. Java 从多线程到并发编程(五)—— 线程调度 优先级倒置(反转) 阻塞 死锁 suspend

    文章目录 前言 ´・ᴗ・` 线程调度策略 优先级倒置问题 优先级倒置解决方案 死锁 dead lock suspend 被阻塞的同时持有资源不放 是上述问题的诱因 总结 ´◡` 前言 ´・ᴗ・` 这一 ...

  6. 刷爆了!Java蝉联5次第一,网友:最强王者!附70k架构师Java学习路线

    图片来源:视觉中国 最近在知乎上,看到一位蚂蚁金服的Java工程师分享,985硕士,校招就拿到了30w的offer.群内也有群友分享,自己通过三年的奋斗,终于年薪70w.这让很多同龄人羡慕,但是羡慕的 ...

  7. 人类高质量 Java 学习路线【一条龙版】

    大家好,我是张讨嫌.现在网上的编程资料实在太多了,而且人人肯定都说自己的最好,那就导致大家又不知道怎么选了.大部分的博主推荐资源,也就是把播放量高的视频说一遍,水一期视频,没有一条很清晰的学习路线. ...

  8. 蜗牛也能爬动的JAVA学习路线,希望能帮助毕业迷茫的你

    蜗牛也能爬动的JAVA学习路线,希望能帮助毕业迷茫的你 笔者想说的话 如果你还是个学生,先去招聘软件上看一看目标岗位的需求,先把需要的技术列出来,再逐项攻破,不要盲目的去学习一些工作中用不到的知识.在 ...

  9. 怒肝 Java 学习路线一条龙!

    文章为转载   请关注鱼皮好友  持续获取 有效学习知识 现在网上的编程资料实在太多了,而且人人肯定都说自己的最好,那就导致大家又不知道怎么选了.大部分的博主推荐资源,也就是把播放量高的视频说一遍,水 ...

最新文章

  1. 服务器处理 json 数据
  2. java入门(1) 程序运行机制及运行过程
  3. jQuery.ajaxPrefilter()函数的使用
  4. linux引导分区被格式化修复,/boot分区、fstab文件、/bin/mount一次性被误除修复方法...
  5. Wine 1.5.15 发布
  6. SpringSession
  7. linux修音软件下载,修音软件下载 Auto Tune 8(修音工具) v8.1.2 免费安装版 下载-脚本之家...
  8. 台式计算机怎么关闭无线网络,台式机无线网卡被禁用了如何解决
  9. grub4dos初级教程
  10. 系统研发类项目标书制作流程--标书该怎么做?
  11. 电脑连接热点无internet访问权限_Win10连接wifi后显示无internet访问权限如何解决...
  12. 力扣 自除数 C语言 题解
  13. 如何将PDF格式转换为WORD文档
  14. arch(linux)挂接小鹤音形输入法
  15. Markdown写出高大上时序图
  16. Git 基本操作(入职亲体验)
  17. Oracle 临时表 (Gobal Temporary Table)
  18. 【Western Digital】常用固件模块编号及作用介绍
  19. Idea 中如何导入项目
  20. 【Java 面试合集】接口以及抽象类

热门文章

  1. 剑侠情缘服务器显示维护,12月24日剑侠情缘3服务器例行维护公告
  2. uni-app H5使用flv.js直播拉流
  3. xshell执行sql脚本
  4. 高级网络配置(包括链路聚合和网络桥接)
  5. 开模锻造压力机行业调研报告 - 市场现状分析与发展前景预测
  6. 定义一个结构体变量(包括年、月、日),编写程序,要求输入年、月、日,程序能判断该年是否为闰年。
  7. SpringBoot发送验证码到QQ邮箱JavaMailSender注入失败
  8. iOS开源资源汇总(完整项目,三方,博客,视频)长期更新
  9. gRPC基本使用(一)--java与go之间的相互调用
  10. 计算机网络基础(2)