信號驅動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信號
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章