实验一 Java I/O和Java线程应用

一、实验目的

      熟悉java运行环境,编程掌握Java输入输出流和Java线程的应用。

二、实验环境

      一般微机即可,软件MyEclipse,JDK1.5以上版本即可。

三、实验内容

      (1)搭建java运行环境
      (2)Java IO流的用法
      (3)Java线程

四、实验步骤

  1. 完成以下程序,写出主要代码,并画出程序的主要流程图。
  • 第一题:利用Java输入输出流编程实现计算器。
    功能:
    (1)先输入第一组操作数,并将其存放在一个文件中。
    (2)然后输入第二组操作数,并将其存放在第二个文件中。
    (3)选择一种加减乘除运算。
    (4)从第一个文件中取第一个操作数,从第二个文件中取第二个操作数,将其按照第三步中选择的运算做加减乘除后存入到第三个文件中。
    (5)从第三个文件中读取出运算结果。
    其他要求:
    (1)要求处理double型或float型数据。
    (2)能够处理程序运行结果中的各种异常。

主要代码:

package test1;

import java.io.*;
import java.math.BigDecimal;
import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) throws IOException {
        Calculator c = new Calculator();
        int flag = 0;
        while (flag==0) {
            System.out.println("请输入您要选择的操作(请输入1-4中的任一数字):");
            System.out.println("1:输入第一组操作数;\n2:输入第二组操作数;\n3:进行运算;\n4:退出系统;");
            Scanner sc = new Scanner(System.in);
            int choice = sc.nextInt();
            switch (choice) {
                case 1:
                    c.firstWrite();
                    break;
                case 2:
                    c.secondWrite();
                    break;
                case 3:
                    c.Calculating();
                    break;
                case 4:
                    flag = 1;
                    break;
            }
        }
    }
    //写入第一组操作数
    public void firstWrite() throws IOException {
        System.out.println("开始向文件1中写入第一组数字:");
        String str;
        FileWriter fw = new FileWriter("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theFirstSetOfData.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        BufferedReader br1 = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            System.out.println("请开始输入操作数(输入end或END结束输入):");
            str = br1.readLine();
            if(str.equalsIgnoreCase("end")) {
                break;
            }
            if(!isNumeric(str)) {
                System.out.println("数字格式不对");
            } else {
                bw.write(str);
                bw.newLine();
            }
        }
        bw.flush();
        bw.close();
    }
    //写入第二组操作数
    public void secondWrite() throws IOException {
        System.out.println("开始向文件2中写入第一组数字:");
        String str;
        FileWriter fw = new FileWriter("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theSecondSetOfData.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        BufferedReader br1 = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            System.out.println("请开始输入操作数(输入end或END结束输入):");
            str = br1.readLine();
            if(str.equalsIgnoreCase("end")) {
                break;
            }
            if(!isNumeric(str)) {
                System.out.println("数字格式不对");
            } else {
                bw.write(str);
                bw.newLine();
            }
        }
        bw.flush();
        bw.close();
    }
    //获取文件有多少行字符
    public int lineNum(String filePath){
        int line = 0;
        try {
            FileReader fr= new FileReader(filePath);
            BufferedReader br = new BufferedReader(fr);
            while(br.readLine() != null) {
                line++;
            }
            fr.close();
            br.close();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return line;
    }
    //进行运算
    public void Calculating() throws IOException {
        FileWriter fw = new FileWriter("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theThirdSetOfData.txt");// 建立文件输出流
        BufferedWriter bw = new BufferedWriter(fw);// 建立缓冲式文件输出流
        BufferedReader br1 = new BufferedReader(new FileReader("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theFirstSetOfData.txt"));
        BufferedReader br2 = new BufferedReader(new FileReader("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theSecondSetOfData.txt"));
        BufferedReader br3 = new BufferedReader(new FileReader("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theThirdSetOfData.txt"));
        String str1,str2,str3;
        int line1 = lineNum("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theFirstSetOfData.txt");
        int line2 = lineNum("D:\\idea_workspace\\NetworkPrograming\\src\\test1\\theSecondSetOfData.txt");
        int maxLine = line1 > line2 ? line1 : line2;
        double[] n1 = new double[maxLine];
        double[] n2 = new double[maxLine];
        //数组初始化
        for (int i = 0; i < maxLine; i++) {
            n1[i] = n2[i] = 0;
        }
        //数组赋值
        int i1 = 0,i2 = 0;
        while ((str1 = br1.readLine()) != null) {
            n1[i1++] = Double.valueOf(str1);
        }
        while ((str2 = br2.readLine()) != null) {
            n2[i2++] = Double.valueOf(str2);
        }
        int flag = 0;
        while (flag==0) {
            System.out.println("1:加法\n2:减法\n3:乘法\n4:除法\n5:返回上一级");
            Scanner sc = new Scanner(System.in);
            int choice = sc.nextInt();
            switch (choice) {
                case 1:
                    //运算
                    for (int i = 0; i < maxLine; i++) {
                        Double result = n1[i] + n2[i];
                        bw.write(result.toString());
                        bw.newLine();

                    }
                    bw.flush();
                    //读出结果
                    while((str3 = br3.readLine())!=null) {
                        System.out.println(str3);
                    }
                    break;
                case 2:
                    //运算
                    for (int i = 0; i < maxLine; i++) {
                        Double result = n1[i] - n2[i];
                        bw.write(result.toString());
                        bw.newLine();
                    }
                    bw.flush();
                    //读出结果
                    while((str3 = br3.readLine())!=null) {
                        System.out.println(str3);
                    }
                    break;
                case 3:
                    //运算
                    for (int i = 0; i < maxLine; i++) {
                        Double result = n1[i] * n2[i];
                        bw.write(result.toString());
                        bw.newLine();
                    }
                    bw.flush();
                    //读出结果
                    while((str3 = br3.readLine())!=null) {
                        System.out.println(str3);
                    }
                    break;
                case 4:
                    //运算
                    for (int i = 0; i < maxLine; i++) {
                        if(n2[i]==0) {
                            System.out.println("运算失败,除数不能为0");
                            bw.write("除数不能为0");
                        } else {
                            Double result = n1[i] / n2[i];
                            bw.write(result.toString());
                            bw.newLine();
                        }
                    }
                    bw.flush();
                    //读出结果
                    while((str3 = br3.readLine())!=null) {
                        System.out.println(str3);
                    }
                    break;
                case 5:
                    flag = 1;
                    br3.close();
                    bw.close();
                    break;
            }
        }
    }
    //判断输入的是否是数字
    public static boolean isNumeric(String str) {
        String bigStr;
        try {
            bigStr = new BigDecimal(str).toString();
        } catch (Exception e) {
            return false;//异常 说明包含非数字。
        }
        return true;
    }
}

主要流程图:

线程与进程Java实验总结_操作数

  • 第二题:利用Java多线程机制实现带滚动字幕的字典。
    功能:
    (1)当用户在“命令”后的文本框中输入“start clock”后,“现在的时间是”后的文本框开始显示系统时钟;当用户输入“stop clock”后,时钟终止显示。
    (2)当用户在“命令”后的文本框中输入“fast”后,能够加速滚动字幕的显示;输入“slow”后,能够减慢字幕滚动;输入“stop”后,滚动字幕停止;输入“restart”后,滚动字幕重新开始滚动;
    (3)当用户在“命令”后的文本框中输入“change ”+字符串时,可更改字幕显示内容。如,输入“change 我可爱的小时钟”后,字幕变为“我可爱的小时钟”。

主要代码:

package test1;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

public class ScrollingAndDictAndTimer {
    public static void main(String[] args) {
        new ThreadFrame();
    }
}
class ThreadFrame extends JFrame implements Runnable, ActionListener {
    JTextField textOfEnglish, textOfChinese, textOfTimer;
    JLabel labelOfEnglish, labelOfTimer, labelOfScrollWords, labelOfBlank;
    Thread scrollWordsThread, timerThread;
    // 滚动文字线程,显示时钟线程
    boolean stopScrolling=false, stopTimer=false;
    String speed = "normal";
    // 是否停止滚动标志位,是否停止显示系统时间标志位
    ThreadFrame() {
        setTitle("一个带滚动字幕和时钟的小字典");
        setLayout(new FlowLayout());

        labelOfBlank = new JLabel("                            ");
        labelOfTimer = new JLabel("现在的时间是");
        textOfTimer = new JTextField(14);
        JPanel jp2 = new JPanel();
        jp2.add(labelOfTimer);
        jp2.add(textOfTimer);
        jp2.add(labelOfBlank);
        add(jp2);//界面中的第二行

        labelOfEnglish = new JLabel("      命令:       ");
        textOfEnglish = new JTextField(14);
        JPanel jp1 = new JPanel();
        jp1.add(labelOfEnglish);
        jp1.add(textOfEnglish);
        add(jp1);//界面中的第一行

        labelOfScrollWords = new JLabel("欢迎使用本系统!");
        // JLabel,负责滚动文字的显示
        add(labelOfScrollWords);
        //界面中的第三行,滚动文字组件不能放在JPanel中,否则不能正常滚动
        textOfEnglish.addActionListener(this);//给文本框注册动作事件
        scrollWordsThread = new Thread(this);
        timerThread = new Thread(this);//初始化线程
        setBounds(100, 100, 400, 200);
        setVisible(true);
        validate();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        scrollWordsThread.start();//启动滚动文字线程
    }

    public void run() {
        if (Thread.currentThread() == scrollWordsThread) {
            //如果当前正在运行的是滚动文字线程
            while (true) {
                int x = labelOfScrollWords.getBounds().x;
                int y = 120;
                if(speed.equalsIgnoreCase("fast")) {
                    x += 10;
                } else if(speed.equalsIgnoreCase("slow")) {
                    x += 2;
                } else {
                    x += 5;
                }
                labelOfScrollWords.setLocation(x, y);
                if (x > 380) {
                    x = 10;
                    labelOfScrollWords.setLocation(x, y);
                }
                try {
                    scrollWordsThread.sleep(500);
                } catch (InterruptedException ex) {
                }
                if (stopScrolling==true) {//如果“stop”,线程终止
                    return;
                }
            }
        }
        if (Thread.currentThread() == timerThread) {
            //如果当前运行的是时钟线程
            while (true) {
                Date date = new Date();
                String str = date.toString().substring(11, 19);
                // 把date中的時間提取出来
                textOfTimer.setText(str);// 把时间显示在文本框中
                try {
                    Thread.sleep(1000);// 休眠1000毫秒
                } catch (InterruptedException ex) {
                }
                if (stopTimer == true) {
                    return;
                    // 如果输入了“stop clock”,线程timerThread停止返回
                }
            }
        }
    }
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == textOfEnglish) {
            String str = textOfEnglish.getText().trim();//提取用户在左侧文本框中的输入
            if (str.equalsIgnoreCase("fast")) {//加速滚动
                stopScrolling = true;
                if (!scrollWordsThread.isAlive()) {
                    // 判定线程是否已经死亡(是否还占有实体)
                    speed = "fast";
                    scrollWordsThread = new Thread(this);// 给线程分配实体
                    stopScrolling = false;
                    scrollWordsThread.start();// 启动线程
                    textOfChinese.setText("文字加速滚动");
                }
//                scrollWordsThread.interrupt();
//                textOfChinese.setText("加速文字滚动");
            } else if (str.equalsIgnoreCase("slow")) {
                stopScrolling = true;
                if (!scrollWordsThread.isAlive()) {
                    // 判定线程是否已经死亡(是否还占有实体)
                    speed = "slow";
                    scrollWordsThread = new Thread(this);// 给线程分配实体
                    stopScrolling = false;
                    scrollWordsThread.start();// 启动线程
                    textOfChinese.setText("文字减速滚动");
                }
            } else if (str.equalsIgnoreCase("stop")) {//停止滚动
                stopScrolling = true;
                textOfChinese.setText("停止文字滚动");
            } else if (str.equalsIgnoreCase("restart")) {//重新开始滚动
                if (!scrollWordsThread.isAlive()) {
                    // 判定线程是否已经死亡(是否还占有实体)
                    scrollWordsThread = new Thread(this);// 给线程分配实体
                    stopScrolling = false;
                    scrollWordsThread.start();// 启动线程
                    textOfChinese.setText("文字重新开始滚动");
                }
            } else if (str.equalsIgnoreCase("start clock")) {
                //启动时钟线程
                if (!timerThread.isAlive()) {
                    // 判定timerThread是否已经进入死亡状态
                    timerThread = new Thread(this);
                    stopTimer = false;
                    timerThread.start();
                    textOfChinese.setText("启动时钟");
                }
            }else if(str.equalsIgnoreCase("stop clock")){//停止时钟线程
                stopTimer = true;//将”停止显示时间“标志位设置为true
                textOfChinese.setText("停止时钟");
            }

            else if(str.substring(0,6).equalsIgnoreCase("change")){
                //如果用户在左侧文本框中的输入单词有对应的中文翻译
                labelOfScrollWords.setText(str.substring(7));
            }else{
                textOfChinese.setText("输入有误!");
            }
        }
    }
}

五、回答问题

  1. 简述线程的两种创建方式。
    1)通过实现Runnable接口线程创建
          1、定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
          2、创建Runnable接口实现类的对象。
          3、创建一个Thread类的对象,需要封装前面Runnable接口实现类的对象。(接口可以实现多继承)
          4、调用Thread对象的start()方法,启动线程
    2)通过继承Thread类创建线程
          1、首先定义一个类去继承Thread父类,重写父类中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
          2、直接创建一个ThreadDemo2类的对象,也可以利用多态性,变量声明为父类的类型。
          3、调用start方法,线程t启动,隐含的调用run()方法。
  2. 简述线程的状态转过过程。
    线程的状态有:new、runnable、running、waiting、timed_waiting、blocked、dead
    转化过程:
    1、当执行new Thread(Runnabler)后,新创建出来的线程处于new状态,这种线程不可能执行
    2、当执行thread.start()后,线程处于runnable状态,这种情况下只要得到CPU,就可以开始执行了。runnable状态的线程,会接受JVM的调度,进入running状态,但是具体何时会进入这个状态,是随机不可知的
    3、running状态中的线程最为复杂,可能会进入runnable、waiting、timed_waiting、blocked、dead状态:
    4、如果CPU调度给了别的线程,或者执行了Thread.yield()方法,则进入runnable状态,但是也有可能立刻又进入running状态
    5、如果执行了Thread.sleep(long),或者thread.join(long),或者在锁对象上调用object.wait(long)方法,则会进入timed_waiting状态
    6、如果执行了thread.join(),或者在锁对象上调用了object.wait()方法,则会进入waiting状态
    7、如果进入了同步方法或者同步代码块,没有获取锁对象的话,则会进入blocked状态
    8、处于waiting状态中的线程,如果是因为thread.join()方法进入等待的话,在目标thread执行完毕之后,会回到runnable状态;如果是因为object.wait()方法进入等待的话,在锁对象执行object.notify()或者object.notifyAll()之后会回到runnable状态
    9、处于timed_waiting状态中的线程,和waiting状态中的差不多,只不过是设定时间到了,就会回到runnable状态
    10、处于blocked状态中的线程,只有获取了锁之后,才会脱离阻塞状态
    11、当线程执行完毕,或者抛出了未捕获的异常之后,会进入dead状态,该线程结束