文章目录

  • 第十二章 并发
      • `synchronized`关键字
      • 同步块
      • 监视器概念
      • `volatile`字段
      • `final`变量
      • 原子性
      • 死锁
    • 线程安全的集合
    • 阻塞队列
      • 映射条目的原子更新
      • 对并发散列映射的批操作
      • 并行数组算法
      • 同步包装器
    • 任务和线程池
      • `Callable, Future`
      • `Executor`执行器
      • `fork-in`框架
    • 异步计算
      • 可完成`Future`
      • 组合可完成`Future`
    • 进程
      • 建立一个进程

第十二章 并发

synchronized关键字

  • 锁用来保护代码片段,一次只能有一个线程执行被保护代码
  • 锁可以管理试图进入被保护代码段的线程
  • 一个锁可以有一个或者多个相关联的条件对象
  • synchronized,设置内部锁
  • wait方法将线程增加到等待集中
  • notifyAll, notify方法可以接触等待线程的阻塞

同步块

  • 会获得obj
synchronized(obj){critical section
}
  • public class Bank{private double[] accounts;private var lock = new Object();public void transfer(int from, int to, int amount){synchronized(lock){accounts[from] -= amount;accounts[to] += amount;}System.out.println(...)}
    }
    
  • 程序员用一个对象锁实现额外的原子操作,称为客户端锁定(十分脆弱)


监视器概念

  • 监视器特性:
  1. 只包含私有字段
  2. 每个对象都有一个关联的锁
  3. 所有的方法由这个锁锁定 (客户端调用object,method(), object对象的方法调用开始时自动获得锁,方法返回时自动释放,这样可以确保一个线程处理字段时,没有其余的线程能够访问这些字段)
  4. 锁可以有任意多个相关联的条件

volatile字段

  • 为实例字段的同步访问提供了一中免锁机制
  • 下例使用内部锁.如果另一个线程已经为该对象加锁,两种方法可能被阻塞
private boolean done;
public synchronized boolean isDone(){ return done;}
public synchronized void setDone() {done = true;}

---->

private volatile boolean done;
public boolean isDone(){ return done;}
public void setDone() {done = true;}

final变量

  • final var accounts = new HashMap<String, Double>();其他线程会在构造器完成之后才看到accounts变量

原子性

  • 对共享变量除了赋值不做其他操作,可以声明为volatile
  • java.util.concurrent.atomic包中很多类保证原子性操作
  • AtomicInteger类提供方法incrementAndGet, decrementAndGet分别以原子方式对一个整数进行自增或者自减

死锁

  • P584
  • 当两个线程互相操作且互相操作不能进行,形成死锁

线程安全的集合

阻塞队列

  • 使用队列可以安全的从一个线程向另一个线程传递数据
  • 当试图向队列中添加元素且队列已满,或者从队列中移除元素而队列已空,阻塞队列将导致线程阻塞
  • put, take方法: 向队列中添加或者移除元素,队列满或者空就阻塞,与不带超时参数的方法offer, poll等效

映射条目的原子更新

  • ConcurrentHashMap类中compute方法可以提供一个键和一个计算新值的函数,比如可以更新一个整数计数器的映射
map.compute(word, (k, v) -> v == null ? 1 : v + 1);
  • computeIfAbsent, computeIfPresent分别只在没有原值和有原值的情况下计算新值
map.compyteIfAbsent(word, k -> new LongAdder()).increment();
  • merge方法表示一个参数键不存在的时候提供初始值,存在就调用提供的函数结合初始值和原值
map.merge(word, 1L, (existingValue, newValue) -> existingValue+newValue);
//简便形式
map.merge(word, 1L, Long::sum);

对并发散列映射的批操作

  • 即使有其他线程在处理映射,批操作也能安全执行
  • search, reduce, forEach操作,可以operation, operationKeys, operationValues, operationEntries分别处理键和值,处理键,处理值,处理Map.Entry对象
  • 需要指定一个参数化阈值,映射包含元素多于这个值就会进行批操作
U searchKeys(long threshold, BiFunction<? super K, ? extends U> f)
U searchValues(long threshold, BiFunction<? super K, ? extends U> f)
U search(long threshold, BiFunction<? super K, ? extends U> f)
U searchEntries(long threshold, BiFunction<? super K, ? extends U> f)
  • 搜索超过一百次出现的单词
String result = map.search(threshold, (k, v) -> v > 1000 ? k : null);

并行数组算法

  • P601

同步包装器

  • 任何集合类都可以通过使用同步包装器变成线程安全的
List<E> synchArray  = Collections.synchronizedList(new ArrayList<E>());
Map<K, V> synchHashMap = Collections.synchroniedHashMap(new HashMap<K, V>());

任务和线程池

Callable, Future

  • Runnable封装一个异步运行的任务, 没有参数和返回值的异步方法
  • Callable有返回值,和前者类似,该接口是一个参数化类型,只有一个方法call
public interface Callable<V>{V call() throws Exception;
}
  • Future保存异步计算的结果

  • 执行Callable方法之一是使用FutureTask. 它实现了Future, Runnable接口,所以可以构造一个线程运行该任务

Callable<Integer> task = ;
var FutureTask = new FutureTask<Integer>(task);
var t = new Thread(futureTask);
t.start();
...
Integer result = task.get(); //it's a Future

Executor执行器

  • newCachedThreadPool构造一个线程池,必要时创建新线程,空闲状态可以保持六十秒
  • newFixedThreadPool构造一个具有固定大小的线程池;提交任务数量大于线程数,放到队列中,任务完成后再运行排队的任务
  • newSingleThreadExecutor只有一个线程的池,顺序执行提交的任务
  • 并发线程数量=处理器内核数 为最优的运行速度
  • 提交任务Future<T> submit(Callable<T>, task)
  • 结束线程池shutdown
    public static void main(String[] args)throws InterruptedException, ExecutionException, IOException{try (var in = new Scanner(System.in)){System.out.print("Enter base directory (e.g. /opt/jdk-9-src): ");String start = in.nextLine();System.out.print("Enter keyword (e.g. volatile): ");String word = in.nextLine();Set<Path> files = descendants(Path.of(start));var tasks = new ArrayList<Callable<Long>>();for (Path file : files){Callable<Long> task = () -> occurrences(word, file);tasks.add(task);}ExecutorService executor = Executors.newCachedThreadPool();// use a single thread executor instead to see if multiple threads// speed up the search// ExecutorService executor = Executors.newSingleThreadExecutor();Instant startTime = Instant.now();List<Future<Long>> results = executor.invokeAll(tasks);long total = 0;for (Future<Long> result : results)total += result.get();Instant endTime = Instant.now();System.out.println("Occurrences of " + word + ": " + total);System.out.println("Time elapsed: "+ Duration.between(startTime, endTime).toMillis() + " ms");var searchTasks = new ArrayList<Callable<Path>>();for (Path file : files)searchTasks.add(searchForTask(word, file));Path found = executor.invokeAny(searchTasks);System.out.println(word + " occurs in: " + found);if (executor instanceof ThreadPoolExecutor) // the single thread executor isn'tSystem.out.println("Largest pool size: "+ ((ThreadPoolExecutor) executor).getLargestPoolSize());executor.shutdown();}}

fork-in框架

  • P612

异步计算

可完成Future

  • 当有一个Future对象会调用get来获得值,这个方法会阻塞直到值可用
  • CompletableFuture类实现了Future接口,注册回调,一旦结果可用,就会在某个线程中调用这个回调,无需阻塞
  • 被称为可完成的,是因为可以手动设置一个完成值,这样的对象在其他并发库中称为承诺
var f = new CompletableFuture<Integer>();
excutor.excute(() -> {int n = workHard(arg);f.complete(n);
});
excutor.excute(() -> {int n = workSmart(arg);f.complete(n);
}) ;
  • 对一个异常完成Future
Throwable t = ...;
f.completeExceptionally(t);

组合可完成Future

  • 非阻塞调用通过回调来实现
  • 程序员为任务完成后要出现的动作注册一个回调
  • 函数thenCompose组合函数T->CompletableFuture<U> 和U -> CompletableFuture<V>
  • whenComplete方法用于处理异常,还有handle方法,他需要一个函数处理结果或者异常,并且计算一个新结果

进程

  • Process类在一个单独的操作系统中执行一个命令,允许我们标准输入.输出和错误流交互
  • ProcessBuilder类允许配置Process对象

建立一个进程

  • 用命令和参数构建一个进程构建器

  • var builder = new Process

  • Builder("gcc", "myapp.c");

  • 第一个字符串必须是一个可执行命令

  • 改变工作目录

builder = builder.directory(path.toFile());
  • 处理进程的标准输入流,输出和错误流
OutputStream processIn = p.getOutputStream();
IntputStream processOut = p.getInputStream();
IntputStream processErr = p.getErrorStream();
  • Attention: 进程的输入流是jvm的一个输出流,进程将输出展示到控制台上
  • startPipeLine利用管道将一个进程的输入作为另一个进程的输出

CoreJava 笔记总结-第十二章 并发-2相关推荐

  1. CoreJava 笔记总结-第十二章 并发-1

    第十二章 并发 线程 package chapter12_concurrent.threads;public class ThreadsTest {public static final int DE ...

  2. 李弘毅机器学习笔记:第十二章—Recipe of Deep Learning

    李弘毅机器学习笔记:第十二章-Recipe of Deep Learning 神经网络的表现 如何改进神经网络? 新的激活函数 梯度消失 怎么样去解决梯度消失? Adaptive Learning R ...

  3. 系统架构师学习笔记_第十二章_连载

    第十二章  系统安全架构设计 12.1  信息系统安全架构的简单描述 信息安全的特征 是为了保证信息的 机密性.完整性.可用性.可控性.不可抵赖性. 以风险策略为基础. 12.1.1  信息安全的现状 ...

  4. 《网络安全工程师笔记》 第十二章:域

    注:本笔记来自温晓飞老师的网络安全课程 第十二章:域 第一章:虚拟化架构与系统部署 第二章:IP地址详解 第三章:进制转换 第四章:DOS基本命令与批处理 第五章:用户与组管理 第六章:服务器远程管理 ...

  5. Boost 第十二章 并发编程

    本文章所有内容源于<BOOST程序库完全开发指南:深入C++"准"标准库(第3版)>第十二章 本章内容包括Boost库中的三个并发编程组件.atomic,它实现了C++ ...

  6. java 并发测试程序_java并发编程实战:第十二章---并发程序的测试

    并发程序中潜在错误的发生并不具有确定性,而是随机的. 安全性测试:通常会采用测试不变性条件的形式,即判断某个类的行为是否与其规范保持一致 活跃性测试:进展测试和无进展测试两方面,这些都是很难量化的(性 ...

  7. 深入理解计算机系统 第十二章 并发编程

    如果逻辑控制流在时间上重叠,那么它们就是并发的(concurrent) 这种常见的现象称为并发(concurrency),出现在计算机系统的许多不同层面上. 并发不仅仅局限于内核,它也可以在应用程序中 ...

  8. 组织行为学笔记:第十二章 组织结构和组织设计

    一.古典组织理论 任何一个单位都要处理诸如权力,责任,分工,专业化以及各部分之间相互依存,相互联系等基本要素. 工作分工 部门领导把自己单位的工作分成不同层次与职能,然后把人员,资源分配到划分成不同层 ...

  9. 【APUE笔记】第十二章 高级I/O

    文章目录 1.非阻塞I/O 2.记录锁 2.1.fcntl记录锁 2.2.锁的隐含继承和释放 2.3.建议性锁和强制性锁 3.流 3.1.流简介 3.2.流消息 3.3.putmsg和putpmsg函 ...

最新文章

  1. Learning by doing 系列文章(之一)如何在 Python 中使用 epoll ?
  2. 视差滚动(Parallax Scrolling)插件补充
  3. Qt_发送邮件(以qq邮箱为例)
  4. 【WP8】Uri关联启动第三方App
  5. python开发Day10(多进程多线程补充)
  6. asp.net ashx处理程序中switch case的替代方案总结
  7. Web前端开发技术包括哪些?
  8. 商品的spu、sku及其之间的关系
  9. Win10 微软拼音添加小鹤双拼以及其他配置
  10. java 运算规则_java四则运算规则
  11. 笔记本按开机键没反应怎么办
  12. IT人员升职必会的软技能
  13. 树莓派3B+安装CentOS 7
  14. 九。温暖地待人,你才会得到意想不到的惊喜结果。
  15. 最好的跑步耳机推荐、盘点五款公认最好的跑步耳机
  16. go 错误处理与测试
  17. VUE调用WEB3.0实现代币查询,批量转账功能
  18. 从零开始编写一个微信小程序(微信开发者工具+JS+WuxUI组件库+云开发)万字整理,建议收藏!
  19. PTA基础编程题目集
  20. 连续系统的时域分析(一)LTI连续系统微分方程解法3——零状态响应的求解方法

热门文章

  1. 数据结构-Hash总结(一):理论学习篇
  2. 工业相机和普通相机的区别详解_数码单反相机和胶片单反相机的区别
  3. python typeerror* wants int_python-TypeError:’int’对象是不可迭代的?
  4. php session缓存,扫盲:php session缓存至memcached中的方法
  5. java完全解耦_java-完全解耦 - osc_bc7dotjc的个人空间 - OSCHINA - 中文开源技术交流社区...
  6. 这道题号称无人能解!300多年来无一人答对,却让这群人这么简单就解出来了?...
  7. 美国返还中国文物,阿里谣言粉碎机获奖,教育部规范研究生培养,腾讯严打微信跑分活动,推动降低港澳漫游费,这就是今天的大新闻。...
  8. 从数学入手,3招打破机器学习的边界
  9. 你试过不用if撸代码吗?
  10. android 短信注册,Android注冊短信验证码功能