Java调用和回调总结(2)


调用的种类

调用有3种, 普通调用(同步调用), 异步调用, 异步回调.

三种调用的特点

普通调用: 也叫做**同步调用 **, 最常见的调用, 会造成阻塞.

异步调用 : 异步调用, 解决了同步调用阻塞的问题, 但是没有返回的结果.

异步回调 : 异步回调, 解决了阻塞, 还可以返回结果.

三者递进的关系从弱到强的如普通调用< 异步调用 < 异步回调, 三者之间最重要的区别其实就只有两点,1:这个调用是不是会造成主线程的阻塞, 2: 我们调用的时候, 可不可以返回执行的结果. 很明显,普通调用, 是会造成阻塞, 但是执行完毕之后, 我们可以立马就获得执行的结果! 但是由于有很多任务的执行时间是非常长的, 这样就会阻塞我们主线程的任务, 所以就导致异步调用的出现, 异步调用和同步调用区别就是, 同步调用阻塞,但是可以获得这个执行的结果, 异步调用不会阻塞, 但是无法得知这个执行的结果! 那么如何解决无法得知任务执行结果的问题呢? 那就是需要在执行的时候, 执行完了之后, 直接通知主线程, 通知主线程, 那就是要使用主线程所在的类的对象, 然后修改其表示执行结果的字段或者属性, 或者执行某个方法让外界得知, 就表示执行的结果已经被外界得知了.

同步和异步怎么解决?

同步会阻塞主线程, 因为我们执行的过程是线性, 线性是因为没有其他的执行线程, 只有一条, 因为同一个时间只有一条任务执行, 是独占的, 所以任务只能阻塞, 等这个任务执行完了才能去执行另一个任务!

异步呢? 异步不会阻塞, 就是因为它突破了只有一个线程的限制, 所以要异步, 就要创建多个线程, 那么在java 里面, 就创建多个Thread, 这样就可以实现异步了!

回调怎么理解?

不管是同步还是异步调用, 都是A调用B单线的调用, 但是这样的话, 比如我们在A线程之中调用B, 那么我们就无法知道B执行的结果, 或者是要让A等待很久, 才能让两个任务完成. 那么我们就要双向调用, 而不是单向调用, 这样的话, 可以双方调用 ,就可以知道结果了, 回调的方式, 一般是通过Interface接口来实现的, 但是也可以通过Class来实现, 但是一般还是通过Interface来实现, 我们需要面向接口来编程.

三种调用实例
同步调用

Teacher类

public class Teacher {
private String name; private Student student; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Teacher() {
} public Teacher(String name) {
this.name = name;
} public Student getStudent() {
return student;
} public void setStudent(Student student) {
this.student = student;
} // 教师给学生布置作业,然后学生做作业
// public void assignHomework(Student s) throws InterruptedException {
public void assignHomework() throws InterruptedException {
student.doHomework();
// 表示普通的调用,会阻塞主线程
System.out.println("老师" + this.getName() + "我要去逛街了!");
}
}

Student类

public class Student {
private String name;
private int id; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public Student() {
} public Student(String name, int id) {
this.name = name;
this.id = id;
} public void doHomework() throws InterruptedException {
System.out.println("我是" + this.getName() + ", 正在写我的家庭作业!");
Thread.currentThread().sleep(5000);
System.out.println("我写完了!");
}
}

HomeworkTest类

public class HomeworkTest {
public static void main(String[] args) throws InterruptedException {
Student student = new Student("张三", 1);
Teacher teacher = new Teacher("小小仙女");
teacher.setStudent(student);
teacher.assignHomework();
}
}
异步调用

EnglishTeacher类

public class EnglishTeacher {
private String name;
private LittleStudent student; public EnglishTeacher() {
} public EnglishTeacher(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public LittleStudent getStudent() {
return student;
} public void setStudent(LittleStudent student) {
this.student = student;
} /**
* 布置作业
*/
public void assignHomework() {
System.out.println(student.getName() + "你去做你的作业, 现在立刻!");
// 异步调用
student.doHomework();
System.out.println("哈哈, 因为我作为一个老师, 要去逛街了!");
}
}

LittleStudent类

public class LittleStudent {
private String name;
private int age; public LittleStudent() {
} public LittleStudent(String name, int age) {
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} // 异步调用的关键, 可以防止阻塞发生, 在需要调用的这个方法之中, 新开一个线程, 就可以防止主线程阻塞了
public void doHomework() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(getName() + "我正在做我的工作");
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 但是此处没有说明做事情的时间, 没有回调的话, 调用者就不就知道任务到底完成了没有!
}
});
t.start();
}
}

EnglishHomeworkTest类

public class EnglishHomeworkTest {
public static void main(String[] args) {
EnglishTeacher teacher = new EnglishTeacher("小仙女儿");
LittleStudent student = new LittleStudent("王二麻子", 7);
teacher.setStudent(student);
// 调用
teacher.assignHomework();
}
}
异步回调

1.使用类的方式实现

Boss类

public class Boss {
private String name;
private Employee employee; public Boss() {
} public Boss(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Employee getEmployee() {
return employee;
} public void setEmployee(Employee employee) {
this.employee = employee;
} public void assignTask() {
System.out.println(this.getName() + ", 作为老板, 我要去做个保健了, 你去干活!");
// 让员工去干活
employee.doTask();
System.out.println(this.getName() + ", 作为老板, 我做保健了, 我回来了!");
} public void getTaskResult() {
System.out.println("完成了任务!");
}
}

Employee类

public class Employee {
private String name;
private Boss boss; public Employee() {
} public Employee(String name, Boss boss) {
this.name = name;
this.boss = boss;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Boss getBoss() {
return boss;
} public void setBoss(Boss boss) {
this.boss = boss;
} // 异步调用
public void doTask() {
// 开一个新的线程, 避免阻塞
Runnable r = new Runnable() {
@Override
public void run() {
// 做具体的业务
long startTime = System.currentTimeMillis();
try {
System.out.println("我是" + getName() + ", 老板啊! 我在玩命干活中!!!");
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
long costTime = endTime - startTime;
System.out.println("这个结果是我自己知道的, 但是我不会给老板说! 实际上我花了" + costTime / 1000 + "ms"); // 回调, 由此可以给出结果!
boss.getTaskResult();
}
};
new Thread(r).start();
}
}

TaskTest类

public class TaskTest {
public static void main(String[] args) {
Boss boss = new Boss("大裤衩");
Employee employee = new Employee("王二", boss);
boss.setEmployee(employee);
boss.assignTask();
// employee.doTask();
}
}

2.使用接口的方式实现, 推荐

BossCallback事件接口

interface BossCallback {
// doEvent, 这就是一个回调通知的方法
public void doEvent();
}

FoxBoss类

public class FoxBoss implements BossCallback {
private String name;
private FoxEmployee foxEmployee; public FoxBoss() {
} public FoxBoss(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public FoxEmployee getFoxEmployee() {
return foxEmployee;
} public void setFoxEmployee(FoxEmployee foxEmployee) {
this.foxEmployee = foxEmployee;
} public void assignTask() {
System.out.println(this.getName() + ", 作为老板, 我要去做个保健了, 你去干活!");
// 让员工去干活
foxEmployee.doTask();
System.out.println(this.getName() + ", 作为老板, 我做保健了, 我回来了!");
} @Override
public void doEvent() {
System.out.println("打电话给老板,告知已经完成工作了");
}
}

FoxEmployee类

public class FoxEmployee {
private String name;
private BossCallback bossCallBack; public FoxEmployee() {
} public FoxEmployee(String name, BossCallback bossCallBack) {
this.name = name;
this.bossCallBack = bossCallBack;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public BossCallback getBossCallback() {
return bossCallBack;
} public void setBossCallback(BossCallback bossCallBack) {
this.bossCallBack = bossCallBack;
} // 异步调用
public void doTask() {
Runnable r = new Runnable() {
@Override
public void run() {
// 做具体的业务
long startTime = System.currentTimeMillis();
try {
System.out.println("我是" + getName() + ", 老板啊! 我在玩命干活中!!!");
Thread.currentThread().sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
long costTime = endTime - startTime;
System.out.println("这个结果是我自己知道的, 但是我不会给老板说! 实际上我花了" + costTime / 1000 + "ms"); // 回调, 由此可以给出结果!
bossCallBack.doEvent();
}
};
new Thread(r).start();
}
}

FoxTaskTest类

public class FoxTaskTest {
public static void main(String[] args) {
FoxBoss boss = new FoxBoss("大裤衩");
FoxEmployee employee = new FoxEmployee("王二", boss);
boss.setFoxEmployee(employee);
boss.assignTask();
}
}

ref:

1.java回调函数,看完就懂, 2.Java接口回调机制详解, 3.Java回调机制解析, 4.异步调用的理解, 5.Java回调机制总结

Java调用和回调总结(2)的更多相关文章

  1. Java 实现函数回调

    在Java里没用委托(delegate)这方法,所以想要实现回调还是有些麻烦.(想了解C#如何实现?请查看:http://www.cnblogs.com/Martin_Q/p/4478494.html ...

  2. paip.java 调用c++ dll so总结

    paip.java 调用c++ dll so总结 ///////JNA (这个ms sun 的) 我目前正做着一个相关的项目,说白了JNA就是JNI的替代品,以前用JNI需要编译一层中间库,现在JNA ...

  3. java模板和回调机制学习总结

    最近看spring的JDBCTemplete的模板方式调用时,对模板和回调产生了浓厚兴趣,查询了一些资料,做一些总结. 回调函数: 所谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个 ...

  4. (翻译)理解Java当中的回调机制

    原文地址:http://cleancodedevelopment-qualityseal.blogspot.com/2012/10/understanding-callbacks-with-java. ...

  5. 编程基础——C/C++,Java,ObjC讨论回调模式

    什么是回调? 因为它是从C开始进入编程世界.术语改只是口.叫习惯了.java里通常叫listener(监听器).C/C++里通常叫callback(回调),ObjC里面叫delegate(托付) 回调 ...

  6. Java中的回调函数学习

    Java中的回调函数学习 博客分类: J2SE JavaJ#  一般来说分为以下几步: 声明回调函数的统一接口interface A,包含方法callback(); 在调用类caller内将该接口设置 ...

  7. JNI实战(二):Java 调用 C

    1. JNI Env 和 Java VM 关系说明 JNIEnv 是 Java的本地化环境,是Java与C的交互的重要桥梁. 在Android上,一个进程对应一个JavaVM,也就是一个app对应一个 ...

  8. Java调用FFmpeg进行视频处理及Builder设计模式的应用

    1.FFmpeg是什么 FFmpeg(https://www.ffmpeg.org)是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.它用来干吗呢?视频采集.视频格式转化.视频 ...

  9. Java中的回调函数学习-深入浅出

    Java中的回调函数一般来说分为下面几步: 声明回调函数的统一接口interface A.包括方法callback(); 在调用类caller内将该接口设置为私有成员private A XXX; 在c ...

随机推荐

  1. fatal error: nvcuvid.h: No such file

    https://www.cnblogs.com/rabbull/p/11154997.html

  2. OpenGL学习(4)——纹理

    拖了半个多月的博客,这次学习如何使用纹理(Texture)贴图来实现更多的细节. 生成纹理对象 和创建VAO.VBO方法类似,调用glGenTextures函数. glGenTextures(1, & ...

  3. 一个老程序员PHP程序员说的话(用来提醒自己)

    我,一个老程序员,也是一个学生,把玩过甚多语言,大多不精.我既非名牌学校,也不是高学历,仅代表一部分比较蛋疼的人.接触PHP也是很早了,从04年的OFSTAR开始的,到现在六年了,期间也接触过不少的语 ...

  4. Docker二

    Docker生成镜像的两种方式 有时候从Docker镜像仓库中下载的镜像不能满足要求,我们可以基于一个基础镜像构建一个自己的镜像 两种方式: 更新镜像:使用docker commit命令 构建镜像:使 ...

  5. 查看创世区块 Genesis Block和channel.tx文件

    将 Block 详细内容导入到 json 文件查看 configtxgen -inspectBlock channel-artifacts/genesis.block > genesis.blo ...

  6. C#,CLR,IL,JIT概念 以及 .NET 家族

    C#,CLR,IL,JIT概念 以及 .NET 家族   Monitor 类通过向单个线程授予对象锁来控制对对象的访问.对象锁提供限制访问代码块(通常称为临界区)的能⼒.当 ⼀个线程拥有对象的锁时,其 ...

  7. Django边角料

    模型层表名自定义: class Record(models.Model): content=models.CharField(max_length=32,db_column='record_conte ...

  8. [转帖]Kubernetes中安装Helm及使用

    Kubernetes中安装Helm及使用 2018年07月02日 17:41:09 灬勿忘丶心安 阅读数 3699更多 分类专栏: K8S   版权声明:本文为博主原创文章,遵循CC 4.0 BY-S ...

  9. postgresSQL常用命令

    1.createdb 数据库名称  产生数据库2.dropdb  数据库名称  删除数据库 3.CREATE USER 用户名称  创建用户4.drop User 用户名称  删除用户 5.SELEC ...

  10. java访问指示符

    是否 可访问 同一package 不同package 当前类 其他类 继承类 其他类 public √ √ √ √ protected √ √ √ × friendly √ √ × × private ...