学习笔记-Java并发(一)


目录

  • 学习笔记-Java并发一

    • 目录
    • Executer
    • Callable和Future
    • 后台线程
    • 线程加入
    • 小计

今天看了这一篇
Java编程思想-java中的并发(一)
记一下学习笔记。


1.Executer

这篇文章中前两节关于基本线程的创建之前在教材中有更好的例子和解释,所以直接跳到第三节:

使用Executor
JAVA SE5的java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程。Executor在客户端和任务执行之间提供了一个间接层;与客户端直接执行任务不同,这个中介对象将执行任务。Executor允许你管理异步任务的执行,而无需显式的管理线程的生命周期。Executor在Java SE5/6中是启动任务的优选方法。

贴上代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** \* Created with IntelliJ IDEA.* \* User: voicebeer* \* Date: 2017/3/26* \* Time: 下午3:04* \* Description:This for tests*/public class Test {private static int taskCount = 0;private final int id = taskCount++;public static class LiftOff implements Runnable {protected int countDown = 5;private int taskCount = 0;private final int id = taskCount++;public LiftOff() {}public LiftOff(int countDown) {this.countDown = countDown;}public String status() {return "#" + id + "(" + (countDown > 0 ? countDown : "Liftoff!") + ").";}@Overridepublic void run() {while (countDown-- > 0) {System.out.println(status());Thread.yield();}}}public static void main(String[] args) {ExecutorService exec = Executors.newFixedThreadPool(2);for (int i = 0; i < 5; i++) {exec.execute(new Main.LiftOff());}exec.shutdown();}
}

贴上结果:


可以发现:

JAVA SE5的java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程。Executor在客户端和任务执行之间提供了一个间接层;与客户端直接执行任务不同,这个中介对象将执行任务。

FixedThreadPool使用了有限的线程集来执行所提交的任务

在这里我首先用FixedThreadPool预先分配出两个线程用作使用,但是在下面的execute中要执行五次,所以就是像结果里一样,一次用两个得来执行。原文中也提到:

CachedThreadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在他回收旧线程时停止创建新线程,因此它是合理的Executor的首选。只有当这种方式会引发问题时,你才需要切换到FixedThreadPool。

所以相比之下还是CachedThreadPool用途更广点吧,需要定制的时候才会用到FixedThreadPool。


2.Callable和Future

如果你希望任务在完成时能够返回一个值,那么可以实现Callable接口而不是Runnable接口。在Java SE5中引入的Callable是一种具有类型参数的泛型,它的类型参数表示的是从方法call()(而不是run())中返回的值,并且必须使用ExecutorService.submit()方法调用他.

老样子先上代码:

import java.util.ArrayList;
import java.util.concurrent.*;/*** \* Created with IntelliJ IDEA.* \* User: voicebeer* \* Date: 2017/3/26* \* Time: 下午3:04* \* Description:This for tests*/public class Test {public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool();ArrayList<Future<String>> results = new ArrayList<>();for (int i = 0; i < 10; i++) {results.add(exec.submit(new TaskWithResult(i)));}for (Future<String> fs : results) {try {//if(fs.isDone()) {System.out.println(fs.get());//}} catch (InterruptedException e) {System.out.println(e);return;} catch (ExecutionException e) {System.out.println(e);} finally {exec.shutdown();}}}
}class TaskWithResult implements Callable<String> {private int id;public TaskWithResult(int id) {this.id = id;}public String call() {return "result of TaskWithResult " + id;}
}

以及结果:

我在代码里注释了一段

//if(fs.isDone()) {System.out.println(fs.get());
//}

这边的isDone就是Callable相对于Runnable的特点,在任务完成时,会有一个返回值,引用原文的话:

你可以用isDone()方法来查询Future是否已经完成。当任务完成时,它具有一个结果,你可以调用get()方法来获取该结果。你也可以不用isDone()进行检查就直接调用get(),这种情况下,get()将阻塞,直至结果准备就绪。你还可以在试图调用get()来获取结果之前,先调用具有超时的get(),或者调用isDone()来查看任务是否完成。


3.后台线程

所谓后台(daemon)线程,是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非后台线程结束时,程序也就终止了,同时会杀死进程中的所有后台线程。反过来说,只要有任何非后台线程还在运行,程序就不会终止。比如,执行main()的就是一个非后台线程。

代码:

import java.util.concurrent.TimeUnit;/*** \* Created with IntelliJ IDEA.* \* User: voicebeer* \* Date: 2017/3/26* \* Time: 下午3:04* \* Description:This for tests*/public class Test {public static class SimpleDaemon implements Runnable {@Overridepublic void run() {try {while (true) {TimeUnit.MILLISECONDS.sleep(100);System.out.println(Thread.currentThread() + " " + this);}} catch (InterruptedException e) {System.out.println("sleep() interrupted");}}}public static void main(String[] args) throws Exception {for (int i = 0; i < 10; i++) {Thread daemon = new Thread(new SimpleDaemon());daemon.setDaemon(true);daemon.start();}System.out.println("All daemons started");TimeUnit.MILLISECONDS.sleep(175);}
}

以及结果:

可以看到创建了十个后台线程。

在上面的代码块里如果把main函数里的

TimeUnit.MILLISECONDS.sleep(175);

设置成比如98ms(之所以不用99是由于存在小数点等问题,其实差1的话并不是表面上的差1),也就是小于SimpleDaemon中的100ms的话,结果就是:

显而易见,没有后台线程了,因为是非后台线程main()先于SimpleDaemon结束,所以杀死了所有后台线程。


4.线程加入

一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复(即t.isAlive()返回为假)。
对join()方法的调用可以被中断,做法是在调用线程上调用interrupt()方法,这时需要用到try-catch子句。
代码:

public class Joining {public static void main(String[] args) {Sleepersleepy = new Sleeper("Sleepy", 1500),grumpy = new Sleeper("grumpy", 1500);Joinerdopey = new Joiner("Dopey", sleepy),doc = new Joiner("Doc", grumpy);grumpy.interrupt();}
}class Sleeper extends Thread {private int duration;public Sleeper(String name, int sleepTime) {super(name);duration = sleepTime;start();}public void run() {try {sleep(duration);} catch (InterruptedException e) {System.out.println(getName() + " was interrupted. " + "interrupted(): " + isInterrupted());}System.out.println(getName() + " has awakened");}
}class Joiner extends Thread {private Sleeper sleeper;public Joiner(String name, Sleeper sleeper) {super(name);this.sleeper = sleeper;start();}public void run() {try {sleeper.join();} catch (InterruptedException e) {System.out.println("interrupted.");}System.out.println(getName() + " join completed.");}
}

结果:

可以看到,首先是按照主函数里的顺序,新建完Sleeper和Joiner后,对grumpy调用interrupt,grumpy立即苏醒,输出:

grumpy was interrupted. interrupted(): false
grumpy has awakened
Doc join completed

/(这里interrupted()之所以是false是由于异常被捕获时将清理isInterrupted()的返回值,所以在捕获语句中一旦异常被捕获,isInterrupted()总是为false/

苏醒后,doc马上就join.

然后程序继续运行,这个时候sleepy休眠了1500ms后也苏醒了,dopey也就马上join进去,所以输出了最后两段。


小计

之后应该还会有三篇,最近立了好多flag。

话说markdown感觉比latex好玩啊

学习笔记-Java并发(一)相关推荐

  1. Java学习笔记---多线程并发

    Java学习笔记---多线程并发 (一)认识线程和进程 (二)java中实现多线程的三种手段 [1]在java中实现多线程操作有三种手段: [2]为什么更推荐使用Runnable接口? [3][补充知 ...

  2. 多线程编程学习笔记——使用并发集合(三)

    接上文 多线程编程学习笔记--使用并发集合(一) 接上文 多线程编程学习笔记--使用并发集合(二) 四.   使用ConcurrentBag创建一个可扩展的爬虫 本示例在多个独立的即可生产任务又可消费 ...

  3. JDBC学习笔记——Java语言与数据库的鹊桥

    JDBC学习笔记--Java语言与数据库的鹊桥     JDBC(Java DataBase Connectivity):SUN公司提供的 一套操作数据库的标准规范,说白了就是用Java语言来操作数据 ...

  4. 深入理解Java虚拟机(第3版)学习笔记——JAVA内存区域(超详细)

    深入理解Java虚拟机(第3版)学习笔记--JAVA内存区域(超详细) 运行时数据区域 程序计数器 java虚拟机栈 本地方法栈 java堆 方法区 运行时常量池 直接内存 对象的创建 对象的内存布局 ...

  5. java volatile lock_Java并发学习笔记 -- Java中的Lock、volatile、同步关键字

    Java并发 一.锁 1. 偏向锁 1. 思想背景 来源:HotSpot的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由同 一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁 ...

  6. 【Java并发编程的艺术】读书笔记——Java并发编程基础

    学习参考资料:<Java并发编程的艺术> 文章目录 1.线程的几种状态 2.如何安全的终止线程 3.线程间通信(重要) 3.1共享内存 3.2消息传递 1.线程的几种状态 线程在运行的生命 ...

  7. tornado学习笔记day01-高并发性能web框架

    tornado的安装 这里我使用的是虚拟环境中的pip安装,配合清华大学镜像源安装的 pip install tornado -i https://pypi.tuna.tsinghua.edu.cn/ ...

  8. 狂神说学习笔记 Java流程控制

    目录 Java流程控制 1.用户交互Scanner Scanner对象 next() nextLine(): 2.顺序结构 3.选择结构 4.循环结构 5.Break & Continue 6 ...

  9. 狂神说Java学习笔记 Java基础

    目录 机器语言 第二代语言(汇编语言) 第三代语言 高级语言 Java特性和优势 JDK(Java Development Kit) JRE(Java Runtime Enviroment) JVM( ...

最新文章

  1. matlab求二元函数极值算法_最优化计算与matlab实现(3)——进退法
  2. STM32之CAN---工作/测试模式浅析
  3. spring viewResolver 类别
  4. 单元测试Struts2Spring项目的Action和Service(包含源码)
  5. php上传文件很慢的原因_PHP编码安全:上传文件安全
  6. JenneyBRO – 模块化wordpress博客主题
  7. .net面试题及答案(一)(转)
  8. Activity的几种启动模式介绍
  9. 十进制计算机算法,计算机知识--二进制,十进制,十六制算法
  10. reincarnation server
  11. FICO-固定资产报废处置流程ABAVN
  12. 安全邮箱是什么邮箱?怎么登录163邮箱?
  13. Java拼图游戏总结,Java拼图游戏课程设计报告
  14. Java中常用的Dos命令
  15. LFTP file already exists and xfer:clobber is unset
  16. Visual C++ 2005的现代语言特性
  17. 抖音爆款脚本文案怎么写?写作时需要注意什么。
  18. Docker-------网络模式
  19. hit_os_lab2 操作系统启动
  20. 机器视觉-halcon——基本概念

热门文章

  1. php历法,Atitit.基于时间戳的农历日历历法日期计算
  2. 在虚拟机中使用Ubuntu和windows系统
  3. 思维导图系列——计算机网络
  4. 2023云南师范大学计算机考研信息汇总
  5. mysql 空集 赋值_MySQL简单复制问题:’show master status’产生’空集’?
  6. 【蓝桥杯省赛真题36】Scratch三国演义字数统计 少儿编程scratch编程蓝桥杯省赛真题讲解
  7. a标签的带参传值和form表单的带参
  8. 如何解决夜神模拟器连不上adb的问题
  9. 004-Mat对象详解
  10. 高性能服务器性能影响因素