线程2---异步1

  在Java中什么是同步?什么是异步?对于这两个概念我们必须要明确。只有明确这两个概念,才会在明确在什么场景下使用同步以及异步。

  在这里我可以形象的举个例子来辨明这两个概念:

1.同步与异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由*调用者*主动等待这个*调用*的结果。
而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。
典型的异步编程模型举个通俗的例子:你打电话问书店老板有没有《分布式系统》这本书,
如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。
在这里老板通过“回电”这种方式来回调。
2. 阻塞与非阻塞阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。还是上面的例子,
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。
在开始解决上述问题之前我们来讨论下使用Callbale接口来创建线程。
@FunctionalInterface
public interface Callable<V> {/*** 返回一个任务的结果,或者抛出一个异常(如果不能计算结果)*/V call() throws Exception;
}

Callable接口是一个函数式接口,其中call()方法的返回值的类型就是Callable接口的泛型的类型。但是Callable接口怎么和线程扯上关系呢?  FutureTask类存在一个构造器:如下所示:

FutureTask(Callable<V> callable) 

其中的参数正式Callable接口对象;FutureTask类又是实现接口RunnableFuture接口:

public class FutureTask<V> implements RunnableFuture<V>

接着看:

public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}

最终的还是继承了Runnable接口和Future接口,为了说明关系,我们画出类图:

package com._thread;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class CallableThread implements Callable<String> {/*** 票的张数为50张,总共100个人买票*/private int ticket = 50;// 表示票的张数
@Overridepublic String call() throws Exception {for (int i = 0; i < 100; i++) {if (ticket > 0) {System.out.println("买票:ticket = " + this.ticket--);}}return "票卖光了!";}public static void main(String[] args) throws InterruptedException, ExecutionException {// 创建Callable接口对象  在这里我创建了两个任务对象Callable<String> callable1 = new CallableThread();Callable<String> callable2 = new CallableThread();// 将创建的callable任务对象存储在FutureTask对象中FutureTask<String> task1=new FutureTask<String>(callable1);FutureTask<String> task2=new FutureTask<String>(callable2);// 启动线程执行任务new Thread(task1).start();new Thread(task2).start();// 上述代码只是执行线程,callable接口是可以产生结果的,futuretask可以获取结果// 调用get()方法可以阻止当前执行的线程获取结果System.out.println("线程A的返回结果是:"+task1.get());System.out.println("线程B的返回结果是:"+task2.get());}
}

这是使用callable接口来创建线程的一种实现过程;好了现在让我们讨论Java异步编程吧!

上面的图可以说明我们的一个买书的过程,在Java中可以视这个操作为同步操作:

package com._thread;public class SlowWorker {public SlowWorker() {}public void doWork() {try {System.out.println("==== 找书, 找书, 找书 ====== ");Thread.sleep(2000);System.out.println("==== OK! ======");} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {SlowWorker worker = new SlowWorker();// 主线程模拟买书的人,doWork()方法模拟书店老板的行为!System.out.println("老板,我要买书" + new java.util.Date());worker.doWork();System.out.println("... 老板在找书的过程中我可以干些事情吗!....");System.out.println("书买到了" + new java.util.Date());System.exit(0);}
}

看运行结果:

老板,我要买书Sun Jan 21 01:49:35 CST 2018
==== 找书, 找书, 找书 ====== 
==== OK! ======
... 老板在找书的过程中我可以干些事情吗!....
书买到了Sun Jan 21 01:49:37 CST 2018

以上的操作确实是一种同步的操作;主线程运行开始后,调用doWork()方法,而doWork()方法需要休眠2s.但是主线程没有继续执行,而是等待了,大家是不是感觉这样做事很没有效率。换言之,如果你在书店买书,老板找一天,你会持续等待下去吗?

接下来我们谈谈ExecutorService这个接口,它可以表示线程池对象;当线程空闲时,它可以接受一个提交给ExecutorService的callable对象,当线程结束的时候,他会返回一个Future.

package com._thread;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;/*** 异步编程* @author gosaint**/
public class AsynchronousWorker {public AsynchronousWorker() {}public void doWork() {try {System.out.println("==== 找书, 找书, 找书 ====== ");Thread.sleep(2000);System.out.println("==== OK! ======");} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {SlowWorker worker = new SlowWorker();// 主线程模拟买书的人,doWork()方法模拟书店老板的行为!System.out.println("老板,我要买书" + new java.util.Date());// 此时我们创建一个线程池,个数为3ExecutorService service = Executors.newFixedThreadPool(3);// 此时存在一个线程池对象,线程池对象提交任务,是一个callable接口Future<String> future = service.submit(new Callable<String>() {@Overridepublic String call() throws Exception {new AsynchronousWorker().doWork(); return null;}});System.out.println("... 老板在找书的过程中我可以干些事情吗!....");System.out.println("做爱做的事情!");try {//调用此方法可以获取我们任务的执行结果,但是会阻止主线程的运行,直到得到一个结果
                future.get(); } catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.println("书买到了" + new java.util.Date());System.exit(0);}}

运行结果如下:

老板,我要买书Sun Jan 21 02:16:13 CST 2018
... 老板在找书的过程中我可以干些事情吗!....
做爱做的事情!
==== 找书, 找书, 找书 ====== 
==== OK! ======
书买到了Sun Jan 21 02:16:15 CST 2018

 主线程开始运行,接着我们向ExecutorService提交了一个买书的任务,之后我们在干其他的事情。而最后呢,Future对象从ExecutorService获取到了执行的结果。我们调用get()方法获取到了执行的结果;倘若我们没有这个调用,那么还是一个并行计算,那么老板找书的结果不会立马给我们返回的; 

转载于:https://www.cnblogs.com/gosaint/p/8320866.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452979.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql通常使用语句_Mysql 常用SQL语句集锦

基础篇//查询时间&#xff0c;友好提示$sql "select date_format(create_time, %Y-%m-%d) as day from table_name";//int 时间戳类型$sql "select from_unixtime(create_time, %Y-%m-%d) as day from table_name";//一个sql返回多个总数$sql "sel…

为什么你需要设计和维护一套自我移动标准?

在一个很长的调研日的休息时分&#xff0c;我在同一个客户谈一个项目&#xff0c;在这个项目中&#xff0c;我正为一个全球经济公司开发一个iOS标准。他们的第一反应是这样的&#xff1a;“什么&#xff1f;你在开发Apple iOS以外的标准&#xff1f;那还要开发什么&#xff1f;…

数据挖掘资料

https://blog.csdn.net/baimafujinji/article/details/53269040 在2006年12月召开的 IEEE 数据挖掘国际会议上&#xff08;ICDM&#xff0c; International Conference on Data Mining&#xff09;&#xff0c;与会的各位专家选出了当时的十大数据挖掘算法&#xff08; top 10 …

如何进行个人知识管理和提高自己能力?

21世纪是一个知识爆炸的世纪&#xff0c;知识爆炸是指人类创造的知识,主要是自然科学知识,在短时期内以极高的速度增长起来。是人们对当前大量出现并飞速发展的各种知识现象所进行的夸张和描述。有人综合计算,全世界的知识总量,七到十年翻一番。这就是风行全球的摩登名词的意思…

redis服务器端和客户端启动

服务器端 sudo redis-server /etc/redis/redis.conf 指定加载的配置文件 ps -ef|grep redis 查看redis服务器进程 sudo kill -9 pid 杀死redis服务器 连接特定IP的redis&#xff1a;

超级丑数

题目&#xff1a; 写一个程序来找第 n 个超级丑数。超级丑数的定义是正整数并且所有的质数因子都在所给定的一个大小为 k 的质数集合内。比如给你 4 个质数的集合 [2, 7, 13, 19], 那么 [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] 是前 12 个超级丑数。注意事项&#xff1a;…

为什么要进行个人知识管理(PKM)

21世纪是一个知识爆炸的世纪&#xff0c;知识爆炸是指人类创造的知识,主要是自然科学知识,在短时期内以极高的速度增长起来。是人们对当前大量出现并飞速发展的各种知识现象所进行的夸张和描述。有人综合计算,全世界的知识总量,七到十年翻一番。这就是风行全球的摩登名词的意思…

NFC读卡------ci522

1、NFC及卡片 NFC是近距离无线通讯技术&#xff0c;是一种非接触式识别和互联技术&#xff0c;可以在移动设备、消费类电子产品、PC和智能控件工具间进行近距离无线通信。NFC提供了一种简单、触控式的解决方案&#xff0c;可以让消费者简单直观地交换信息、访问内容与服务。 …

mysql 索引效果是否叠加_MySQL基础实用知识集合(二)

上期小编给大家汇总介绍了mysql的6个基础的知识点,下面继续给大家分享一下另外7个知识点&#xff1a;7、什么是死锁&#xff1f;怎么解决&#xff1f;死锁&#xff1a;两个或多个事务相互占用了对方的锁&#xff0c;就会一直处于等待的状态。常见的解决死锁的方法&#xff1a;(…

IP协议

IP协议只负责传送IP数据包&#xff0c;无法监视和控制网络中出现的一些问题&#xff0c;这些工作由Internet的控制协议来完成IP是T C P / I P协议族中最为核心的协议。所有的T C P、U D P、I C M P及I G M P数据都以I P数据报格式传输。它的特点如下:不可靠&#xff08;u n r e…

gitlab修改用户密码_CRM用户模块(用户密码修改)

四 密码修改1 需求分析修改当前登陆用户的登陆密码2 页面原型3 流程图 4 编写ControllerResponseBodyRequestMapping("updatePwd")public MessageModel updatePwd(HttpServletRequest request, String oldPassword, String newPassword, String confirmPassword){Mes…

third day- 01--文件操作

1 1、请分别介绍文件操作中不同的打开方式之间的区别&#xff1a;2 3 模式 含义4 r 文本只读模式5 rb 二进制模式  #这种方法&#xff0c;是用来传输或存储&#xff0c;不给人看的。6 r r 是读写模式&#xff0c;只要沾上r&#xff0c;文件必须存在7 rb …

微信小程序中form 表单提交和取值实例详解

2019独角兽企业重金招聘Python工程师标准>>> 我们知道&#xff0c;如果我们直接给 input 添加 bindinput&#xff0c;比如&#xff1a;<input bindinput"onUsernameInput" />&#xff0c;那么可以在 onUsernameInput 中直接使用 e.detail.value&…

matlab如何用代码导入文件_20+行Matlab代码实现文件扫描

最近刚好看到一篇回答&#xff0c;用阈值二值化处理图片水印&#xff0c;受到启发写此代码。阈值二值化适合处理只有黑白两色的图片&#xff0c;考虑到文件盖章&#xff0c;这里作者使用像素颜色替换及灰度值处理图片&#xff0c;进一步提高处理精度和能力。我们需要&#xff1…

启动django服务器报错raise errorclass(errno, errval) django.db.utils.InternalError

问题描述&#xff1a; 启动django服务器python manage.py runserver报错: raise errorclass(errno, errval) django.db.utils.InternalError: (1366, “Incorrect string value: ‘\xE7\x94\xA8\xE6\x88\xB7’ for column ‘name’ at row 1”) 原因&#xff1a;与mysql数据库…

java单例模式之线程安全问题

单例的目的是为了保证运行时Singleton类只有唯一的一个实例&#xff0c;用于一些较大开销的操作。 饿汉式&#xff08;没有线程安全问题&#xff09;: ‘ 由于使用static关键字进行了修饰&#xff0c;只能获取到一个对象&#xff0c;从而达到了单例&#xff0c;并且在Singleton…

448. Find All Numbers Disappeared in an Array 寻找有界数组[1,n]中的缺失数

&#xff3b;抄题&#xff3d;&#xff1a; Given an array of integers where 1 ≤ a[i] ≤ n (n size of array), some elements appear twice and others appear once. Find all the elements of [1, n] inclusive that do not appear in this array. Could you do it with…

Linux基本命令+Makefile

1.linux下查看进程占用cpu的情况(top)&#xff1b; 格式 top [&#xff0d;] [d delay] [q] [c] [S] [s] [i] [n] 主要参数 d&#xff1a;指定更新的间隔&#xff0c;以秒计算。q&#xff1a;没有任何延迟的更新。如果使用者有超级用户&#xff0c;则top命令将会以最高的优先…