JavaのWebアプリケーション開発フレームワークによる、Webサイト開発の顛末記です。

EclipseのMavenを使った、Spring-MVC、Thymeleaf、MyBatis 等のプログラミングテクニックを、
備忘録的に記録しています。実際に動くソースコードを多用して説明していますので、
これからEclipseや、Spring-MVCを始めたいと思っている人にとって、少しでも参考になれば幸いです。
Spring-MVCの散歩道 > 応用の森(総合テクニック編) > WebSocketを使った、リアルタイムCPU使用率推移グラフ

package jp.dip.arimodoki.websocket;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import jp.dip.arimodoki.common.CConst;
import jp.dip.arimodoki.common.JsonConvert;
import jp.dip.arimodoki.common.JsonConvertIf;
import jp.dip.arimodoki.model.data.CpuUsed;
import jp.dip.arimodoki.model.data.CpuUsedIf;

/**
 * WebSock CPU使用率計算Runnableスレッドクラスです。
 */
public class CPUHandlerRun implements Runnable,CConst {
    private final int LOOP_MAX = 40;

    volatile Thread kicker = null;
    private int loop = 0;
    private int curpos = 0;

    private long old_time=0;
    private double old_use=0.0;

    //JSON パーサー/ジェネレータクラスインスタンスを生成
    private JsonConvertIf jsonConvert = new JsonConvert();

    //CPU使用率情報格納リスト
    private List<CpuUsedIf> cpuUsed = new ArrayList<>();

    //WebSocketSession CPUHandlerクラスから継承
    private WebSocketSession session;
    //セッション一覧Map CPUHandlerクラスから継承
    private Map<String, WebSocketSession> sessionMap ;

    //デフォルトコンストラクタ
    public CPUHandlerRun() {}

    /**
     * コンストラクタ
     * @param session WebSocketSession(CPUHandlerクラスから継承)
     * @param sessionMap セッション一覧Map(CPUHandlerクラスから継承)
     */
    public CPUHandlerRun(WebSocketSession session, Map<String, WebSocketSession> sessionMap) {
        this.session = session;
        this.sessionMap = sessionMap;
    }

    /**
     * CPU使用率の計算を行います
     * @return 倍精度実数のCPU使用率(%)を返します
     * @throws Exception
     */
    private double calc_usage() throws Exception {
        //Linuxのstat情報ファイルを読み込む
        File file = new File("/proc/stat");
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line = reader.readLine().trim();
        String[] vals = line.split("\\s+");
        int usr  = Integer.parseInt(vals[1]);
        int nice = Integer.parseInt(vals[2]);
        int sys  = Integer.parseInt(vals[3]);
        reader.close();

        long now = System.currentTimeMillis() / 10;
        double usage = (usr + nice + sys - old_use) / (now - old_time);
        old_use = usr + nice + sys;
        old_time = now;
        return usage*10;    //暇なのでちょいと多めに(^^);
    }

    /**
    * スレッドを開始する
    */
    public void start() {
        if (this.kicker == null) {
            this.loop = 0;
            this.curpos = 0;
            //CPU使用率情報リスト生成
            this.cpuUsed.clear();
            for(int i = 0 ; i < LOOP_MAX ; i++) {
                CpuUsedIf used = new CpuUsed("0",0);
                this.cpuUsed.add(used);
            }
            //スレッド作成
            this.kicker = new Thread(this);
            this.kicker.start();    //スレッド開始
        }
    }
    /**
    * スレッドを停止する
    */
    public void stop() {
        if (this.kicker != null) {
            this.kicker = null;   //スレッド開放
        }
    }

    /**
     * スレッドを実行する
     */
    public void run() {
        while (this.kicker != null) {
            Thread thisThread = Thread.currentThread();
            if (this.kicker == thisThread) {
                if (loop < LOOP_MAX) {
                    //CPU使用率を取得
                    double usage = 0.0;
                    try {
                        usage = this.calc_usage();
                    } catch (Exception e) {
                        logger.log_error(e,"calc_usage");
                    }
                    //現在のリスト位置のオブジェクトを取得
                    CpuUsedIf used = this.cpuUsed.get(this.curpos);
                    //現在秒をセットする
                    Calendar cal = Calendar.getInstance();
                    used.setTime(Integer.toString(cal.get(Calendar.SECOND)));
                    //現在のCPU使用率をセットする
                    used.setUsed(usage);

                    //this.cpuUsedの配列をシリアライズ(JSON化)する
                    String msg = "";
                    try {
                        msg = this.jsonConvert.Serialize(this.cpuUsed);
                    } catch (Exception e) {
                        logger.log_error(e,"used Serialize");
                    }
                    this.curpos++;      //現在位置を進める
                    for (Entry<String, WebSocketSession> entry : this.sessionMap.entrySet()) {
                        try {
                            String targetId = entry.getKey();
                            if(targetId.equals(this.session.getId())) {         //自分のセッションだったら
                                //Client に sendMessageで返却する
                                entry.getValue().sendMessage(new TextMessage(msg.getBytes()));
                            }
                        } catch (Exception e) {
                            logger.log_error(e,"sendMessage");
                        }
                    }
                    loop++;
                    try {
                        Thread.sleep(3000);     //3秒 Sleep
                    } catch (InterruptedException e) {
                        logger.log_error(e,"sleep");
                    }
                } else {    //やるべきことはやったよ
                    this.stop();             //時間がきたらスレッドを停止する
                }
            }
        }
    }
}