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回調機制總結