实验一 Java I/O和Java线程应用
一、实验目的
熟悉java运行环境,编程掌握Java输入输出流和Java线程的应用。
二、实验环境
一般微机即可,软件MyEclipse,JDK1.5以上版本即可。
三、实验内容
(1)搭建java运行环境
(2)Java IO流的用法
(3)Java线程
四、实验步骤
- 完成以下程序,写出主要代码,并画出程序的主要流程图。
- 第一题:利用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多线程机制实现带滚动字幕的字典。
功能:
(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)通过实现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()方法。 - 简述线程的状态转过过程。
线程的状态有: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状态,该线程结束