Java調用和回調總結(2)


Java調用和回調總結(2)


調用的種類

調用有3種, 普通調用(同步調用), 異步調用, 異步回調.

三種調用的特點

普通調用: 也叫做**同步調用 **, 最常見的調用, 會造成阻塞.
img

異步調用 : 異步調用, 解決了同步調用阻塞的問題, 但是沒有返回的結果.
img

異步回調 : 異步回調, 解決了阻塞, 還可以返回結果.
img

三者遞進的關系從弱到強的如普通調用< 異步調用 < 異步回調, 三者之間最重要的區別其實就只有兩點,1:這個調用是不是會造成主線程的阻塞, 2: 我們調用的時候, 可不可以返回執行的結果. 很明顯,普通調用, 是會造成阻塞, 但是執行完畢之后, 我們可以立馬就獲得執行的結果! 但是由於有很多任務的執行時間是非常長的, 這樣就會阻塞我們主線程的任務, 所以就導致異步調用的出現, 異步調用和同步調用區別就是, 同步調用阻塞,但是可以獲得這個執行的結果, 異步調用不會阻塞, 但是無法得知這個執行的結果! 那么如何解決無法得知任務執行結果的問題呢? 那就是需要在執行的時候, 執行完了之后, 直接通知主線程, 通知主線程, 那就是要使用主線程所在的類的對象, 然后修改其表示執行結果的字段或者屬性, 或者執行某個方法讓外界得知, 就表示執行的結果已經被外界得知了.

同步和異步怎么解決?

同步會阻塞主線程, 因為我們執行的過程是線性, 線性是因為沒有其他的執行線程, 只有一條, 因為同一個時間只有一條任務執行, 是獨占的, 所以任務只能阻塞, 等這個任務執行完了才能去執行另一個任務!
異步呢? 異步不會阻塞, 就是因為它突破了只有一個線程的限制, 所以要異步, 就要創建多個線程, 那么在java 里面, 就創建多個Thread, 這樣就可以實現異步了!
img

回調怎么理解?

不管是同步還是異步調用, 都是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回調機制總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM