`
jaenson
  • 浏览: 188998 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

Java线程间通信-回调的实现方式

阅读更多

实例方法回调


原理:将回调类定义为一个实现某种接口的类(接口可以省掉),然后在每个多线程类上都注入一个回调对象。当线程执行完毕后,通过回调对象执行自己的回调方法,从而达到线程通信的目的。实现代码如下:

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import java.security.DigestInputStream; 

/** 
* 求文件的信息摘要码(MD5) 
* 
* @author leizhimin 2008-9-11 22:53:39 
*/ 
public class InstanceCallbackDigest implements Runnable { 
    private File inputFile;         //目标文件 
    //每个线程绑定一个回调对象 
    private InstanceCallbackDigestUserInterface instanceCallback; 

    /** 
     * 构件时一次注入回调对象 
     * 
     * @param instanceCallback 
     * @param inputFile 
     */ 
    public InstanceCallbackDigest(InstanceCallbackDigestUserInterface instanceCallback, File inputFile) { 
        this.instanceCallback = instanceCallback; 
        this.inputFile = inputFile; 
    } 

    public void run() { 
        try { 
            FileInputStream in = new FileInputStream(inputFile); 
            MessageDigest sha = MessageDigest.getInstance("MD5"); 
            DigestInputStream din = new DigestInputStream(in, sha); 
            int b; 
            while ((b = din.read()) != -1) ; 
            din.close(); 
            byte[] digest = sha.digest();   //摘要码 
            //完成后,回调主线程静态方法,将文件名-摘要码结果传递给住线程  
            instanceCallback.receiveDigest(digest); 
        } catch (FileNotFoundException e) { 
            e.printStackTrace(); 
        } catch (NoSuchAlgorithmException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 
} 



import java.io.File; 

/** 
* 静态非同步回调 
* 
* @author leizhimin 2008-9-11 23:00:12 
*/ 
public class InstanceCallbackDigestUserInterface { 
    private File inputFile;     //回调与每个文件绑定 
    private byte digest[];      //文件的消息摘要码 

    public InstanceCallbackDigestUserInterface(File inputFile) { 
        this.inputFile = inputFile; 
    } 

    /** 
     * 计算某个文件的消息摘要码 
     */ 
    public void calculateDigest() { 
        InstanceCallbackDigest callback = new InstanceCallbackDigest(this, inputFile); 
        Thread t = new Thread(callback); 
        t.start(); 
    } 

    /** 
     * 接收消息摘要码 
     * 
     * @param digest 
     */ 
    public void receiveDigest(byte[] digest) { 
        this.digest = digest; 
        //将消息摘要码输出到控制台实际上执行的是this.toString()方法 
        System.out.println(this); 
    } 

    /** 
     * 显示结果 
     * 
     * @return 结果 
     */ 
    public String toString() { 
        String result = inputFile.getName() + ": "; 
        if (digest != null) { 
            for (byte b : digest) { 
                result += b + " "; 
            } 
        } else { 
            result += "digest 不可用!"; 
        } 
        return result; 
    } 

    public static void main(String[] args) { 
        String arr[] = {"C:\\xcopy.txt", "C:\\x.txt", "C:\\xb.txt", "C:\\bf2.txt"}; 
        args = arr; 
        for (int i = 0; i < args.length; i++) { 
            File f = new File(args[i]); 
            InstanceCallbackDigestUserInterface cb = new InstanceCallbackDigestUserInterface(f); 
            cb.calculateDigest(); 
        } 
    } 
}



输出结果:
xcopy.txt: 123 -91 90 -16 -116 -94 -29 -5 -73 25 -57 12 71 23 -8 -47  
x.txt: 123 -91 90 -16 -116 -94 -29 -5 -73 25 -57 12 71 23 -8 -47  
xb.txt: 112 -81 113 94 -65 -101 46 -24 -83 -55 -115 18 -1 91 -97 98  
bf2.txt: 31 -37 46 -53 -26 -45 36 -105 -89 124 119 111 28 72 74 112  

Process finished with exit code 0



实例方法回调更加的灵活,一个文件对应一个回调对象,这样便于跟踪关于计算过程中信息而不需要额外的数据结构。其次,如果有必要,还可以重新计算指定的摘要(需要继承默认实现,然后覆盖方法)。

注意:这里的public void calculateDigest()方法,这个方法可能在逻辑上认为它属于一个构造器。然而,在构造器中启动线程是相当危险的,特别是对开始对象回调的线程。这里存在一个竞争条件:构造器中假如有很多的事情要做,而启动新的线程先做了,计算完成了后要回调,可是这个时候这个对象还没有初始化完成,这样就产生了错误。当然,实际中我还没有发现这样的错误,但是理论上是可能的。 因此,避免从构造器中启动线程是一个明智的选择。

转载自:http://lavasoft.blog.51cto.com/62575/98796
分享到:
评论

相关推荐

    关于Java线程间通信-回调.docx

    总的来说,回调在Java线程间通信中起到桥梁的作用,使得线程能够以非阻塞的方式互相协作,提高了程序的并发性能和响应速度。理解并熟练掌握回调以及其他线程通信机制是Java并发编程的关键,这对于开发高效、稳定的多...

    C++JNI多线程回调java

    总的来说,理解和实现"C++ JNI多线程回调java"涉及到对JNI接口的深入理解,对多线程编程的掌握,以及对Java并发模型的认识。这是一个高级的跨语言编程话题,需要开发者具备扎实的C++和Java基础。在实际项目中,这样...

    Android JNI多线程编程回调JAVA函数

    - Android的`Looper`和`Handler`可以用来在不同线程间传递消息,实现线程间的通信,例如将本地线程的结果发送到主线程更新UI。 5. **示例:JniCallBackDemo**: - `JniCallBackDemo`可能是项目中的一个示例工程,...

    JNI层创建的线程中回调java方法

    JNI在很多场景下都有应用,如性能优化、使用现有的C/C++库、或者在不同线程间通信。当我们需要在JNI层创建线程并从这些线程回调Java方法时,就需要对JNI的线程管理和Java方法调用有深入理解。 首先,我们需要了解...

    Java基础核心理解+什么是回调即回调机制讲解

    - **多线程编程**:在多线程环境中,线程间通信可以通过回调来实现。 - **框架开发**:许多框架提供扩展点,允许开发者通过回调机制自定义行为。 #### 四、回调与异步的区别 虽然回调通常与异步调用一起出现,但...

    java接口回调

    在多线程编程中,也常常使用回调来处理线程间的通信。 首先,我们来看一下`MyThread.java`可能的内容。这个文件通常会定义一个自定义的线程类,它可能会启动一个新线程去执行耗时的操作。为了实现回调,这个类可能...

    android 线程间通讯

    在Android中,主要使用以下几种方式实现线程间通信: 1. **Handler-Looper-Messenger机制**: - **Handler**:在特定线程(通常为主线程)中创建,用于接收并处理Message对象,这些Message由其他线程发送。 - **...

    Java中回调方法使用范例

    回调方法在许多场景下都非常有用,比如异步处理、事件驱动编程、多线程间的通信等。它们提供了更大的灵活性,让程序员能够定制特定行为,而不必硬编码到调用者内部。在Java中,回调方法的使用是实现可扩展性和解耦的...

    Android-Socket长连接通信心跳包消息回调Java服务端

    通过分析和学习这个项目,你可以更直观地了解上述知识点的实现方式,包括如何创建Socket连接、实现心跳包、处理消息回调以及服务端的多线程处理等。 总结,实现“Android-Socket长连接通信心跳包消息回调Java服务端...

    Java回调机制

    同步回调的一个常见例子是在线程间通信,例如通过`synchronized`关键字或者`wait/notify`机制。异步回调常常与Java的并发库(如`ExecutorService`,`Future`,`CompletableFuture`等)结合,或者在网络编程中的`...

    Android(Java)线程的两种实现方式

    Android为了方便在不同线程间通信,引入了`Handler`、`Looper`和`Message`的概念。这种机制允许我们在后台线程发送消息,并在主线程中处理这些消息,从而更新UI。 1. `Looper`:每个线程都有一个消息队列,`Looper`...

    java多线程进度条实例

    这个实例提供了一个基础的进度条实现,但在实际应用中,可能需要考虑更多因素,如线程优先级、线程池的使用、异常处理、线程间的通信等。此外,如果是在图形用户界面环境下,还需要考虑UI更新的流畅性和用户体验。...

    JNI实现回调及JNI开启线程

    因为Java对象在不同线程间通常是不可直接共享的,需要进行适当的同步操作,如使用`MonitorEnter`和`MonitorExit`。此外,由于Java虚拟机会在特定时刻(如GC)暂停所有非守护线程,因此在JNI线程中长时间阻塞可能会...

    匿名内部类实现接口回调

    在Java编程中,接口回调是一种常见的设计模式,用于在对象之间传递异步事件或实现通信。这个"匿名内部类实现接口回调"的示例旨在演示如何通过匿名内部类来简化回调函数的实现。下面我们将详细探讨接口回调的概念、...

    【Java核心知识面试】-java多线程50题.zip

    - wait()、notify()、notifyAll():Object类的方法,用于线程间通信。需在同步环境中使用,避免死锁。 - Condition接口:与Lock配合使用,提供了更灵活的线程通信方式。 6. **线程池**: - ExecutorService:...

    Java线程从入门到实践.doc

    - 回调函数、监听器或者使用`BlockingQueue`等并发容器也可以实现线程间的数据交换。 7. **线程返回数据** - 通常通过共享变量、`Future`、`Callable`接口结合`ExecutorService`来获取线程执行结果。 8. **同步...

    java CallBack(回调函数)

    总结一下,Java回调函数是通过接口实现的一种设计模式,允许对象间相互通信和协作。这种机制在处理异步操作、事件驱动编程以及需要在特定条件满足后执行特定操作的场景下尤其有用。理解并熟练运用回调函数能够帮助...

    线程互斥--多线程学习

    为了在非UI线程中安全地更新界面,可以使用异步回调、事件队列或者线程间通信(如Android的Handler机制)来调度UI更新操作。 例如,在Java的Android开发中,可以通过`runOnUiThread()`方法将代码块放入UI线程执行;...

    JavaSocket学习---NIO实现非阻塞的通信

    在Java编程语言中,Socket是网络通信的基本组件,它提供了进程间网络通信的能力。而NIO(Non-blocking Input/Output,非阻塞I/O)是Java提供的一个高性能的I/O模型,与传统的阻塞I/O相比,NIO具有更高的并发性能。本...

Global site tag (gtag.js) - Google Analytics