为什么需要并行?
– 业务要求
– 性能
并行计算还出于业务模型的需要
– 并不是为了提高系统性能,而是确实在业务上需要多个执行单元。
– 比如HTTP服务器,为每一个Socket连接新建一个处理线程
– 让不同线程承担不同的业务工作
– 简化任务调度 Linus Torvalds :并行计算只有在 *图像处理* 和 *服务端编程* 2个领域可以使用,并且它在这2个领域确实有着大量广泛的使用。但是在其它任何地方,并行计算毫无建树!
计算密集型 在多核时代,一般没有必要特别区分并发和并行 同步(synchronous)和异步(asynchronous)
 并发(Concurrency)和并行(Parallelism)  临界区  阻塞(Blocking)和非阻塞(Non-Blocking)
– 阻塞和非阻塞通常用来形容多线程间的相互影响。比如一个线程占用了临界区资源,那么其它所有需要这个资源的线程就必须在这个临界区中进行等待,等待会导致线程挂起。这种情况就是阻塞。此时,如果占用资源的线程一直不愿意释放资源,那么其它所有阻塞在这个临界区上的线程都不能工作。
– 非阻塞允许多个线程同时进入临界区  锁(Deadlock)、饥饿(Starvation)和活锁(Livelock)  并行的级别 并发级别
– 阻塞
– 非阻塞
– 无障碍
– 无锁
– 无等待 有关并行的2个重要定律
 Amdahl定律(阿姆达尔定律)
 Gustafson定律(古斯塔夫森) 进程切换是一个重量级的操作,需要消耗大量的计算资源 在Java中的线程会直接映射到操作系统的线程上去 Thread t1 = new Thread();
t1.start(); // 开启线程进入就绪状态 Thread t2 = new Thread();
t2.run(); // 不能开启线程,在本线程内执行run方法 继承Thread重写run方法,MyThread extends Thread
new Thread(new Runnable() {}).start(); Thread.stop()不建议使用@Deprecated,太过暴力,类似于Linux强制杀死进程:kill -9 thread_id public static native void sleep(long millis) throws InterruptedException
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interruted!");
break;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Interruted When Sleep");
// 设置中断状态,抛出异常后会清除中断标记位 ********
Thread.currentThread().interrupt();
}
Thread.yield();
}
} suspend()、resume() 等待线程结束(join)和谦让(yeild)
join的本质:
while(isAlive()) {
wait(0);
}
线程执行完毕后,系统会调用notifyAll(); ===> 可以不需要在线程实例上使用wait()和notifyAll() 守护线程
 在后台默默地完成一些系统性的服务,比如垃圾回收线程、 JIT线程就可以理解为守护线程
 当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出
Thread t = new DaemonT();
t.setDaemon(true);
t.start(); 高优先级的线程更容易再竞争中获胜 基本的线程同步操作
 synchronized
– 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
public void run() {
for(int j = 0; j < 10000000; j++) {
synchronized(instance) {
i++;
}
}
} – 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
public synchronized void increase(){
i++;
} – 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
public static synchronized void increase(){
i++
}  Object.wait() Obejct.notify()
public static class T1 extends Thread {
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis()+":T1 start!");
try {
System.out.println(System.currentTimeMillis() + ":T1 wait for object ");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+":T1 end!");
}
}
}
public static class T2 extends Thread {
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis() +":T2 start! notify one thread");
object.notify();
System.out.println(System.currentTimeMillis()+":T2 end!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
1425224592258:T1 start!
1425224592258:T1 wait for object
1425224592258:T2 start! notify one thread
1425224592258:T2 end!
1425224594258:T1 end notify() VS notifyAll()
notify()随机唤醒一个线程,notifyAll()唤醒全部等待此监视器的线程,让他们去竞争这个监视器的使用权 》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》 Java内存模型和线程安全
 原子性
原子性是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其它线程干扰。  有序性
在并发时,程序的执行可能就会出现乱序。
一条指令的执行是可以分为很多步骤的(*数据旁路技术*&*指令重排*可以使流水线更加流畅,指令重排不能出现语义问题)
– 取指 IF
– 译码和取寄存器操作数 ID
– 执行或者有效地址计算 EX
– 存储器访问 MEM
– 写回 WB  可见性
可见性是指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。
– 编译器优化
– 硬件优化(如写吸收,批操作)
Java虚拟机层面的可见性(volatile)  Happen-Before
 程序顺序原则:一个线程内保证语义的串行性
 volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性
 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
 传递性:A先于B,B先于C,那么A必然先于C
 线程的start()方法先于它的每一个动作
 线程的所有操作先于线程的终结(Thread.join())
 线程的中断(interrupt())先于被中断线程的代码
 对象的构造函数执行结束先于finalize()方法  线程安全的概念
指某个函数、函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成。 ReentrantLock(重入锁 )是synchronized关键字的增强,目前两者性能不相上下。 ReentrantLock
可重入
可多次加锁
可中断
发生死锁时,可启用一个守护线程去中断某一线程从而达到解锁目的
可限时
避免死锁和长期等待锁
公平锁
公平锁虽然不会产生饥饿但是由于公平锁需要解决排队问题(先到先得),所以性能较非公平锁差,没有特殊要求没必要使用公平锁。 JDK并发包--并发容器及典型源码分析
 集合包装
 HashMap --> 适用小并发量,串行解决方案,非高并发解决方案
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}  List
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}  Set
public static <T> Set<T> synchronizedSet(Set<T> s) {
return new SynchronizedSet<>(s);
}  ConcurrentHashMap
ConcurrentHashMap(HashMap底层使用数组实现,因此为实现大规模高并发,可将整个数组分成N个段<Segment>,一个就可供N个线程同时写入数据,理论提高效率N倍)
put()方法各个Segment有各自的锁,get()方法无锁,但是在size()方法中需要拿到所有Segment的锁后才能统计数据,但size()方法并非一个高频率调用的函数。
之所是高性能,是因为不会随随便便就加锁,而是经过自旋等待在有必要的时候才加锁。  BlockingQueue
阻塞队列,是一个接口,线程安全,不是一个高性能的容器,但是BlockingQueue是一个非常好的**在多个线程中共享数据的容器**
若为空队列,此时有线程尝试读取数据,则此读的线程会等待,直到有另外线程往队列中写入数据,则读的线程就会被唤醒并且读取数据;
若队列已经写满了,则写入的线程就会等待,直到有线程读取数据有空闲空间后才能写入队列;
因此Blocking会引起线程阻塞。
BlockingQueue作为生产者消费者容器很方便。
put()、take()
实现:ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue。  ConcurrentLinkedQueue
类似ConcurrentHashMap的高性能Queue,内部使用了大量的无锁操作。offer()、poll()
 BlockingQueue VS ConcurrentLinkedQueue
在并发编程中我们有时候需要使用线程安全的队列。如果我们要实现一个线程安全的队列有两种实现方式:一种是使用**阻塞算法**,另一种是使用**非阻塞算法**。使用阻塞算法的队列可以用一个锁(入队和出队用同一把锁)或两个锁(入队和出队用不同的锁)等方式来实现,而非阻塞的实现方式则可以使用循环CAS的方式来实现。

》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

对于我们的业务来说:线程的创建和销毁与业务无关,只关心是否执行了任务,毕竟创建销毁需要消耗计算资源,因此我们希望将更多的资源用于执行任务而不是用在辅助性质的线程创建和销毁上。

线程池限流

内置线程池的种类(Executors对应的方法)
  newFiexedThreadPool 固定大小的线程池
  newSingleThreadExecutor 只有一个线程的线程池
  newCachedTHreadPool 弹性线程池
  newScheduledTHreadPool 定时任务,执行某个线程

newFiexedThreadPool()、newSingleThreadExecutor()、newCachedTHreadPool()三个方法底层都是通过类ThreadPoolExecutor实现的,其典型构造方法(4个)为
  public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                 int maximumPoolSize, // 最大线程数
                 long keepAliveTime, // 超过核心线程数的空闲线程最大存活时间
                 TimeUnit unit, // 时间单位
                 BlockingQueue<Runnable> workQueue) // 当线程池满载运行时存放新任务的阻塞队列,newCachedTHreadPool()例外,使用了SynchronousQueue

内置线程池使用:
  MyThread task = new MyThread();
  ExecutorService es = Executors.newFixedThreadPool(5);
  for (int idx = 0; idx < 10; ++idx) {
    es.submit(task);
  }

ExecutorService类
  shutdown()
  isShutdown() : boolean
  isTerminated() : boolean
  submit(Callable task) : Future

Java并发笔记-未完待续待详解的更多相关文章

  1. Java学习笔记(未完待续)

    变量的作用域(scope)是指变量可以在程序中引用的范围.在方法中定义的变量称为局部变量(local variable).局部变量的作用域从声明变量的地方开始,直到包含该变量的块结束为止.局部变量都必 ...

  2. Go web编程学习笔记——未完待续

    1. 1).GOPATH设置 先设置自己的GOPATH,可以在本机中运行$PATH进行查看: userdeMacBook-Pro:~ user$ $GOPATH -bash: /Users/user/ ...

  3. Java学习笔记 线程池使用及详解

    有点笨,参考了好几篇大佬们写的文章才整理出来的笔记.... 字面意思上解释,线程池就是装有线程的池,我们可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程 ...

  4. 003java面试笔记——【java基础篇】从团八百失败面试总结的java面试题(未完待续)

    8.java 线程     1)线程概念,线程与进程      线程:线程是“进程”中某个单一顺序的控制流.也被称为轻量进程.线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程.线 ...

  5. 漫漫征途,java开发(未完待续)

    前言 2018年,大二上,有幸加入服务外包实验室的考核,在考核中,主动加入xxx项目的后端,一是为了积累项目经验,二是为了学到更多东西,进入了之后发现原来要学的这么多,时间这么紧!但唯有学习! 心得体 ...

  6. jQuery 学习笔记(未完待续)

    一.jQuery概述    宗旨: Write Less, Do More.    基础知识:        1.符号$代替document.getElementById()函数        2.使 ...

  7. 2019秋招Java面经(未完待续)

    2019秋招Java面经(凭记忆回忆, 可能不准) 随着我们从大三升到大四...秋招也开始了. 秋招进行的还比较顺利, 刚开始没几天, 我的秋招就结束了. 到现在我玩了差不多十多天了, 总想着总结一下 ...

  8. 剑指Offer:面试题33——把数组排成最小的数(java实现)(未完待续)

    问题描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 思路1: ...

  9. linux学习笔记---未完待续,缓慢更新

    做为linux菜鸟,由于work的需要,慢慢的开始接触学习linux. <鸟哥的linux私房菜>学习笔记. 一.基础命令操作 1.显示日期的命令 date 执行date命令后,显示结果为 ...

随机推荐

  1. 每日英语:How Your Knees Can Predict the Weather

    The Wolff family of Paramus, N.J., was eyeing the gathering clouds and debating whether to cancel a ...

  2. 解决最小化安装Centos7后无法上网的问题,以及安装成功后的基本配置

    发现问题 刚装完最小化的系统后,如果直接ping外网,可能回出现如下情况 解决问题 首先编辑虚拟机的DHCP池: 在弹出的“虚拟网络编辑器”窗口中选择NAT模式的,编辑为其分配地址池: 然后编辑网卡的 ...

  3. js 数组的增删改查

    js数组元素的添加和删除一直比较迷惑,今天终于找到详细说明的资料了,先给个我测试的代码^-^ var arr = new Array(); arr[0] = "aaa"; arr[ ...

  4. Python利用jieba获取中文词汇等

    import jieba import os import jieba.analyse data = cleaned_comments # 数据来源于评论数据 seg = jieba.lcut(dat ...

  5. 08Vue.js快速入门-Vue综合实战项目

    8.1. 前置知识学习 npm 学习 官方文档 推荐资料 npm入门 npm介绍 需要了解的知识点 package.json 文件相关配置选项 npm 本地安装.全局安装.本地开发安装等区别及相关命令 ...

  6. 在分布式系统里看CAP定理

    本文转自:http://zhuanlan.51cto.com/art/201703/534587.htm 计算机界有很多高大上又难于理解的术语,CAP就是其中之一, 什么一致性(Consistency ...

  7. Java heap space cdh 5.11.1

    在执行hive count 查询的时候报错:Error: Java heap space 解决办法是 set io.sort.mb=10; 执行hadoop的Exeample的时候报错,也是java ...

  8. C++学习笔记(HelloWorld,类型和值)

    现在有一个从控制台读取输入的小程序: #include "../std_lib_facilities.h" int main() { cout << "Ple ...

  9. hbase源码系列(十四)Compact和Split

    先上一张图讲一下Compaction和Split的关系,这样会比较直观一些. Compaction把多个MemStore flush出来的StoreFile合并成一个文件,而Split则是把过大的文件 ...

  10. k8s 题目

    这几个月参与了几场面试,设计了多道面试题,觉得可以综合考察应聘人对 kubernetes的掌握情况.在这里分享下,供应聘人自查以及其他面试官参考. 这些面试题的设计初衷并不是考察 kubernetes ...