某科技公司高管面试时留的家庭作业

题目:
Linux环境下的Java主线程中自定义启动两个子线程,两个子线程分别负责执行各自的定时任务,第一个线程负责的任务定时像mysql数据中写任务,写数据的task是由shell启动java写的task,第二个线程负责的任务由python写的,由java线程负责调用(这次我的python任务只是向特定目录下追加写一个文件)。
现将解题思路,技术细节分享如下:

首先是宏观的工作空间结构图
这里写图片描述
driver目录下存放的是主线程的Driver类
starttask1.sh与starttask2.sh分别是两个任务的启动脚本
tasks目录下存放两个task的源文件以及mysql的连接驱动mysql-connector.jar(已重命名)
tmp是用来存放python写入的随机数文件

先解决向数据库中写文件的问题(WriteMysqlTask.java负责)
先上WriteMysqlTask.java的源码:

import java.sql.*;
public class WriteMysqlTask {
    public static void main(String[] args){
        try{
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("加载驱动成功");
        }catch(ClassNotFoundException e1){
            System.out.println("加载驱动失败");
            e1.printStackTrace();
        }

        String url="jdbc:mysql://localhost:3306/data"; 
        Connection conn;
        try {
        conn = DriverManager.getConnection(url, "root", "123456");
        Statement stmt = conn.createStatement();
        System.out.println("将向数据库中插入[name=xiaoxing,age=18]的数据...");
        String insert_data = "insert into peoinfo values('xiaoming',18) ";
        stmt.execute(insert_data);
        System.out.println("已插入数据成功,请在data数据库peoinfo表中查验");
        stmt.close();
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    }
}

接下来,是很重要的一步解决该文件的编译运行问题。
Class.forName()采用的是运行时动态加载,里面的内容编译时不进行检查,因此,编译大多不会出现问题,就直接用
javac WriteMysqlTask.java进行编译
效果图如下:
这里写图片描述
运行的时候需要注意一下:
java -classpath ‘./:mysql-connector.jar’ WriteMysqlTask
尤其是-classpath参数的填写不要填错,填错将直接导致Class.forName(“com.mysql.jdbc.Driver”);执行出错
以下是效果图:
这里写图片描述
紧接着,介绍一下该task的启动sh,即:startwriteMysql.sh
这里写图片描述
备注:编译执行完后rm -f *.class删除所有任务字节码文件
以下,是该shell脚本的执行效果图:
这里写图片描述

python相关的task任务源程序如下所示(writeRandom.py):
这里写图片描述
以追加的方式向tmp目录下的pwrite.txt写如11位随机数

两个启动task的sh分别为starttask1.sh和starttask2.sh:
这里写图片描述
starttask1.sh的内容:
这里写图片描述
starttask2.sh的内容:
这里写图片描述
这里,我觉得有必要解释一下cd ../tasks
我们先来看一下目录:
这里写图片描述
cd ../tasks命令的意思是:../返回上级目录,再进入tasks目录。因为Driver.java驱动是在driver目录下执行的,所以当用java Driver启动starttask1.sh与starttask2.sh时,尽管 starttask*.sh文件本身不在driver目录中,但当前执行目录确实是在driver目录中。因此,需返回上级目录后方可进入tasks目录执行相应的任务。

接下来,重点介绍一下Driver.java

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Timer;
import java.util.TimerTask;

public class Driver {
    static void execshell(int taskid) {
        try {
            String shpath = "../starttask" + taskid + ".sh";
            Process ps;
            System.out.println("shpath:"+shpath);
            ps = Runtime.getRuntime().exec(shpath);
            ps.waitFor();
            BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
            StringBuffer sb = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }
            String result = sb.toString();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class WritemysqlTask extends TimerTask {
        static int count=1;
        @Override
        public void run() {
            count++;
            double oldtime=System.currentTimeMillis();
            System.out.println("WritemysqlTask任务第"+count+"次启动时间为:"
                    + oldtime);
            execshell(1);
            double pretime=System.currentTimeMillis();
            System.out.println("WritemysqlTask任务:结束时间为:"+pretime);
            double all=pretime-oldtime;
            System.out.println("WritemysqlTask任务:此次任务共计耗时:"+all);
        }
    }

    static class ExecutepyTask extends TimerTask {
        static int count=1;
        @Override
        public void run() {
            count++;
            double oldtime=System.currentTimeMillis();
            System.out.println("ExecutepyTask任务第"+count+"次启动时间为:"
                    + oldtime);
            execshell(2);
            double pretime=System.currentTimeMillis();
            System.out.println("ExecutepyTask任务:结束时间为:"+pretime);
            double all=pretime-oldtime;
            System.out.println("ExecutepyTask任务:此次任务共计耗时:"+all);
        }

    }

    static class RunnableThread1 implements Runnable {
        @Override
        public void run() {
            Timer timer = new Timer();
            timer.schedule(new WritemysqlTask(), 1000, 1000);
        }
    }

    static class RunnableThread2 implements Runnable {
        @Override
        public void run() {
            Timer timer = new Timer();
            timer.schedule(new ExecutepyTask(), 1000, 1000);
        }
    }

    public static void main(String[] args) {
        System.out.println("main即将启动两个线程");
        double old = System.currentTimeMillis();
        new Thread(new RunnableThread1()).start();
        new Thread(new RunnableThread2()).start();
        double pre = System.currentTimeMillis();
        String consume = pre - old + "";
        System.out.println("main已启动两个线程,耗时:" + consume);
    }

}

说明:因为是已命令行java XX启动执行java程序的,为了方便编译运行,特将类统统写成静态内部类方便行事。
String shpath = “../starttask” + taskid + “.sh”;
根据传递进来的taskid值分别拼装出../starttask1.sh和../starttask2.sh
即返回上一级目录执行sh脚本,本级目录是在driver中。
Runtime.getRuntime().exec(shpath);
通过Runtime的静态方法getRuntime()的到运行时,之后.exec(XX)执行相应的shell命令。
Timer timer = new Timer();
timer.schedule(new XXX(), 1000, 1000);
调度器从Task启动的的1秒后每隔1秒调度一次任务。

这里写图片描述
我们接下来看一下startDriver.sh
这里写图片描述

最后,跑一个全部流程:
清空peoinfo表中的所有数据
这里写图片描述
这里写图片描述

./startDriver.sh启动流程:
这里写图片描述
执行13次调度以后按Ctrl+c停止执行:
这里写图片描述
查看数据库中的数据:
这里写图片描述
查看tmp目录下文件的数据:
这里写图片描述

至此,全部跑通。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值