信号驱动I/O模型——Java实现

I/O模型有阻塞I/O模型、非阻塞I/O模型、多路复用I/O模型、信号驱动I/O模型、异步I/O模型。这次我将使用Java实现信号驱动I/O模型。下图是原理图
信号驱动I/O模型

写之前我在网上搜了很久,才发现一篇C/C++语言实现的信号驱动I/O模型。
后来发现Java提供的信号机制在sun.misc包下,属于非标准包。
其中Signal类可以创建哪些信号和操作系统有关。Signal.handle()方法用户注册信号处理器,Signal.raise用于激发信号。
SignalHandler是一个函数式接口,其中的handle方法用于处理收到的信号。当然可以收到系统发送的信号,如linux下的kill -15 Java进程的ID(可是使用top | grep java查找到)。

我写的示例说明:用户线程在听《歌手·当打之年 第9期》华晨宇的好想爱这个世界啊歌曲,它发起一个I/O请求下载我的github上存放的一首歌,周杰伦的歌曲琴伤。将信号注册到信号处理器。下载完毕后,发送INT中断信号,信号处理接收到信号后加以判断,用户线程将数据从内核拷到用户空间(拷贝过程阶段用播放琴伤模拟)。

感想:我觉得这个信号就像我以前写安卓时的广播。信号驱动I/O模型方便在进程间通信,复杂的线程间通信。信号驱动I/O的特色、吸引人的地方好像在于信号上,抢了I/O的风头。书中提到”系统会为请求对应的socket注册一个信号函数“,不知道如何实现。

代码:WateForDataThread.java准备数据的线程,SignalDrivenIOTest.java体验信号驱动I/O的类。其中使用到了jlayer-1.0.1包,这个包中播放音乐的方法里面创建的有守卫进程,小心了(其他播放音乐的包有jmf,解析歌曲的包jaudiotagger,这里没有用到它们)。

package signaldriven;

import sun.misc.Signal;
import sun.misc.SignalHandler;

import javax.sound.sampled.*;
import javax.swing.*;
import java.io.File;
import java.io.IOException;

public class SignalDrivenIOTest {
    public static void main(String[] args) {
        SignalDrivenIOTest signalDrivenIOTest = new SignalDrivenIOTest();
        signalDrivenIOTest.run();
    }

    private String localSong = "华晨宇 - 好想爱这个世界啊.wav";
    private String remoteDownloadLink = "https://github.com/zzuwenjie/ucaslife/raw/master/sources/%E5%91%A8%E6%9D%B0%E4%BC%A6%20-%20%E7%90%B4%E4%BC%A4.wav";
    private String storePath = "周杰伦 - 琴伤.wav";
    private String SIGIO = "INT";
    private Clip clip;
    private Clip preferClip;
    public void run() {
        new Thread(new WaitForDataThread(remoteDownloadLink, storePath)).start(); // 我不知道怎么让内核准备数据,故下载一首歌
        Signal.handle(new Signal(SIGIO), signalHandler); // 下载好了通知我执行handler
        File file = new File(localSong);
        try {
            AudioInputStream audioInput = AudioSystem.getAudioInputStream(file);
            preferClip = AudioSystem.getClip();
            clip = AudioSystem.getClip();
            clip.open(audioInput);
            clip.loop(Clip.LOOP_CONTINUOUSLY);
            clip.start();
        } catch (IOException | UnsupportedAudioFileException | LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    private SignalHandler signalHandler = (signal)->{
        if (signal.getName().equals(SIGIO)) {
            handleSIGIO();
        }
    };

    private void handleSIGIO() {
        File file = new File(storePath);
        long pausePosition = 0;
        if (!file.exists())
            return; // 不应该没准备好数据
        if (clip != null) {
            pausePosition = clip.getMicrosecondPosition();
            clip.stop();
        }
        try {
            AudioInputStream inputStream = AudioSystem.getAudioInputStream(file);
            preferClip.open(inputStream);
            preferClip.start();
            JOptionPane.showMessageDialog(null, "应用进程复制数据中。点击复制完毕,返回成功指示");
            preferClip.close();
           // 假设将数据拷到内核用户空间,阻塞主线程。
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
            e.printStackTrace();
        }
        clip.setMicrosecondPosition(pausePosition);
        clip.start();
        JOptionPane.showMessageDialog(null, "接着听音乐中...不如学习会儿?");
        clip.close();
    }
}
package signaldriven;

import sun.misc.Signal;

import javax.swing.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class WaitForDataThread implements Runnable {
    private String urlString;
    private String filename;
    public WaitForDataThread(String url, String filename) {
        urlString = url;
        this.filename = filename;
    }

    @Override
    public void run() {
//        try {
//            URL url = new URL(urlString);
//            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//            conn.setConnectTimeout(1000 * 3);
//            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//            BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
//            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filename));
//            byte[] buf = new byte[1024 * 20];
//            int length = -1;
//            while ((length = bis.read(buf)) != -1) {
//                bos.write(buf, 0, length);
//            }
//            bis.close();
//            bos.close();
//            conn.disconnect();
//            Signal.raise(new Signal("INT"));  // 下载完时发送INT信号
//        } catch (IOException e){
//            e.printStackTrace();
//        }
        //github下载数据太慢了,几乎连接不上
        JOptionPane.showMessageDialog(null, "内核准备数据,应用进程播放歌曲。点击发送信号通知应用进程准备好了");
        Signal.raise(new Signal("INT"));  // 下载完时发送INT信号
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值