实验五 多线程程序设计(汽院含答案) 下载本文

实验五 多线程程序设计

实验目的

1. 掌握Java语言中多线程编程的基本方法 2. 掌握Runnable接口实现多线程的方法 3. 掌握Thread类实现多线程的用法

实验导读

1. 进程和线程的概念

进程是程序一次动态执行的过程,对应从代码加载、执行到执行结束这样一个完整的过程,也是进程自身从产生、发展到消亡的过程。

线程是比进程更小的执行单元,一个进程在执行过程中,可以产生多个线程。每个线程都有自身的产生、执行和消亡的过程。

2. 线程的状态与生命周期

? 新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。此时它

已经有了相应的内存空间和其他资源。

? 运行:线程创建之后就具备了运行的条件,一旦轮到它来享用CPU资源时,即JVM将CPU使用权

切换给该线程时,此线程的就可以脱离创建它的主线程独立开始自己的生命周期了(即run方法执行的过程)。

? 中断:有4种原因的中断,CPU资源从当前线程切换给其他线程、执行了sleep(int millsecond)方法、

执行了wait()方法、进入阻塞状态 。 ? 死亡:run方法结束。

3. 线程的创建

在Java语言中,与线程支持密切相关的是java.lang.Thread类和java.lang.Runnable接口。Runnable接口定义很简单,只有一个run方法。任何一个类如果希望自己的实例能够以线程的形式执行,都可以来实现Runnable接口。

继承Thread类和实现Runnable接口,都可以用来创建Thread对象,效果上并没有什么不同。继承Thread类的方法很明显的缺点就是这个类不能再继承其他的类了,而实现Runnable接口不会有这个麻烦。

另外,在继承Thread类的代码中,this其实就是指当前正在运行的线程对象,如果使用实现Runnable接口的方式,要得到当前正在执行的线程,需要使用Thread.currentThread()方法。

线程创建后仅仅是占有了内存资源,在JVM管理的线程中还没有这个线程,此线程必须调用start()方法(从父类继承的方法)通知JVM,这样JVM就会知道又有一个新一个线程排队等候切换了。

注意:多次启动一个线程,或者启动一个已经运行的线程对象是非法的,会抛出IllegalThreadStateException异常对象。

4. 线程的优先级

同一时刻在等待队列中的线程会有很多个,它们各自任务的重要性有所不同。为了加以区分,使工作安排和资源分配时间更为合理,每个线程可以被赋予不同的优先级,让任务比较急的线程拥有更高的优先级,从而更快地进入执行状态。

Java中提供了10个等级的线程优先级,最低为Thread.MIN_PRIORITY=1,最高为

Thread.MAX_PRIORITY=10,默认优先级为Thread.NORM_PRIORITY=5。

使用Thread类中的setPriority(int)方法可以为线程指定优先级。

5. 线程的常用方法 ? start() 方法:

线程调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以脱离创建它的线程独立开始自己的生命周期了。

? run()方法:

Thread类的run()方法与Runnable接口中的run()方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户程序不得引用的方法。系统的Thread类中,run()方法没有具体内容,所以用户程序需要创建自己的Thread类的子类,并重写run()方法来覆盖原来的run()方法。当run方法执行完毕,线程就变成死亡状态。

? sleep(int millsecond) 方法:

现程占有CPU期间,执行sleep方法来使自己放弃CPU资源,休眠一段时间。休眠时间的长短由sleep方法的参数决定,millsecond是毫秒为单位的休眠时间。如果线程在休眠时被打断,JVM就抛出InterruptedException异常。因此,必须在try~catch语句块中调用sleep方法。

? isAlive() 方法:

线程处于“新建”状态时,线程调用isAlive()方法返回false。当一个线程调用start()方法,并占有CUP资源后,该线程的run方法就开始运行,在线程的run方法结束之前,即没有进入死亡状态之前,线程调用isAlive()方法返回true。当线程进入“死亡”状态后(实体内存被释放),线程仍可以调用方法isAlive(),这时返回的值是false。

一个已经运行的线程在没有进入死亡状态时,不要再给线程分配实体,由于线程只能引用最后分配的实体,先前的实体就会成为“垃圾”,并且不会被垃圾收集机收集掉。

? currentThread() 方法:

currentThread()方法是Thread类中的类方法,可以用类名调用,该方法返回当前正在使用CPU资源的线程。

? interrupt() 方法: intertupt方法经常用来“吵醒”休眠的线程。当一些线程调用sleep方法处于休眠状态时,一个占有CPU资源的线程可以让休眠的线程调用interrupt 方法“吵醒”自己。

6. 线程的同步

线程同步是指几个线程都需要调用一个同步方法(使用关键字synchronized修饰的方法) 。 当一个线程A使用一个synchronized修饰的方法时,其他线程想使用这个方法时就必须等待,直到线程A 使用完该方法 (除非线程A使用wait主动让出CPU资源)。

一个线程在使用的同步方法中时,可能根据问题的需要,必须使用wait()方法使本线程等待,暂时让出CPU的使用权,并允许其它线程使用这个同步方法。其它线程如果在使用这个同步方法时如果不需要等待,那么它用完这个同步方法的同时,应当执行notifyAll()方法通知所有的由于使用这个同步方法而处于等待的线程结束等待。

? 挂起:

有时候两个线程并不是同步的,即不涉及都需要调用一个同步方法,但线程也可能需要暂时的挂起。所谓挂起一个线程就是让线程暂时让出CPU的使用权限,暂时停止执行,但停止执行的持续时间不确定,因此不能使用sleep方法暂停线程。挂起一个线程需使用wait方法,即让准备挂起的线程调用 wait 方法,主动让出CPU的使用权限. ? 恢复:

为了恢复该线程,其它线程在占有CUP资源期间,让挂起的线程的目标对象执行notifyAll()方法,使得挂起的线程继续执行;如果线程没有目标对象,为了恢复该线程,其它线程在占有CUP资源期间,

让挂起的线程调用notifyAll()方法,使挂起的线程继续执行。

实验内容

1. 汉字识别程序

编写一个Java应用程序,在主线程中再创建一个Frame类型的窗口,在该窗口中再创建一个线程giveWord。线程giveWord每隔6秒钟给出一个汉字,用户使用一种汉字输入法将该汉字输入到文本框中。请按模板要求,将代码补充完整。

WordThread.java

import java.awt.*;

public class WordThread extends Thread { char word; Label com;

WordThread(Label com) { this.com = com; }

public void run() { while (true) {

word = (char) (Math.random()*(29968-19968)+19968); System.out.println(word); com.setText(\ + word); try { }

ThreadFrame.java

public class ThreadFrame extends Frame implements ActionListener { Label wordLabel; Button button;

TextField inputText, scoreText;

【补充代码】 // 用WordThread声明一个giveWord对象 int score = 0;

ThreadFrame() {

wordLabel = new Label(\, Label.CENTER);

wordLabel.setFont(new Font(\, Font.BOLD, 72));

button = new Button(\开始\); inputText = new TextField(3); scoreText = new TextField(5); scoreText.setEditable(false);

【补充代码】 // 调用sleep方法使得线程中断6000豪秒 } catch (InterruptedException e) {} } }

【补充代码】// 创建giveWord,将wordLabel传递给WordThread构造方法的参数 button.addActionListener(this); inputText.addActionListener(this); add(button, BorderLayout.NORTH);

add(wordLabel, BorderLayout.CENTER);

Panel southP = new Panel();

southP.add(new Label(\输入标签所显示的汉字后回车:\)); southP.add(inputText); southP.add(scoreText);

add(southP, BorderLayout.SOUTH); setBounds(100, 100, 350, 180); setVisible(true); validate();

addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent e) { System.exit(0); } }); }

public void actionPerformed(ActionEvent e) { if (e.getSource() == button) {

if (!(【补充代码】)) // giveWord调用方法isAlive() {

giveWord = new WordThread(wordLabel); }

try { 【补充代码】// giveWord调用方法start() } catch (Exception exe) { }

} else if (e.getSource() == inputText) {

if (inputText.getText().equals(wordLabel.getText())) { score++;

}

scoreText.setText(\得分:\ + score); inputText.setText(null); } }

}

WordThread.java

public class ThreadWordMainClass {

public static void main(String args[]) { new ThreadFrame(); }

} 答案代码: WordThread.java import java.awt.*; public class WordThread extends Thread { char word; Label com; WordThread(Label com) { this.com = com; } public void run() { while (true) { word = (char) (Math.random()*(29968-19968)+19968); System.out.println(word); com.setText(\ + word); try { sleep(6000); // 调用sleep方法使得线程中断6000豪秒 } catch (InterruptedException e) {} } } } ThreadFrame.java public class ThreadFrame extends Frame implements ActionListener { Label wordLabel; Button button; TextField inputText, scoreText; WordThread giveWord; // 用WordThread声明一个giveWord对象 int score = 0; ThreadFrame() { wordLabel = new Label(\, Label.CENTER); wordLabel.setFont(new Font(\, Font.BOLD, 72)); button = new Button(\开始\); inputText = new TextField(3); scoreText = new TextField(5); scoreText.setEditable(false); giveWord=new WordThread(wordLabel); // 创建giveWord,将wordLabel传递给WordThread构造方法的参数 button.addActionListener(this); } inputText.addActionListener(this); add(button, BorderLayout.NORTH); add(wordLabel, BorderLayout.CENTER); Panel southP = new Panel(); southP.add(new Label(\输入标签所显示的汉字后回车:\)); southP.add(inputText); southP.add(scoreText); add(southP, BorderLayout.SOUTH); setBounds(100, 100, 350, 180); setVisible(true); validate(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void actionPerformed(ActionEvent e) { if (e.getSource() == button) { } if (!(giveWord.isAlive())) // giveWord调用方法isAlive() { giveWord = new WordThread(wordLabel); } try { giveWord.start();//【补充代码】// giveWord调用方法start() } catch (Exception exe) { } } else if (e.getSource() == inputText) { if (inputText.getText().equals(wordLabel.getText())) { score++; } scoreText.setText(\得分:\ + score); inputText.setText(null); } WordThread.java public class ThreadWordMainClass { public static void main(String args[]) { new ThreadFrame(); } }

2. 双线程接力

编写一个应用程序,除了主线程外,还有两个线程:first和second。first负责模拟一个红色的按钮从坐标(10,60)运动到(100,60);second负责模拟一个绿色的按钮从坐标(100,60)运动到(200,60)。

阅读并分析以下程序,将程序中的代码补充完整,编译并运行程序,查看结果。

MoveButton.java

import java.awt.*;

import java.awt.event.*;

public class MoveButton extends Frame implements Runnable,ActionListener { 【补充代码】 //用Thread类声明first,second两个线程对象 Button redButton,greenButton,startButton; int distance=10; MoveButton()

{ 【补充代码】 //创建first线程,当前窗口做为该线程的目标对象 【补充代码】 //创建first线程,当前窗口做为该线程的目标对象 redButton=new Button(); greenButton=new Button();

redButton.setBackground(Color.red);

greenButton.setBackground(Color.green); startButton=new Button(\);

startButton.addActionListener(this); setLayout(null); add(redButton);

redButton.setBounds(10,60,15,15); add(greenButton);

greenButton.setBounds(100,60,15,15); add(startButton);

startButton.setBounds(10,100,30,30); setBounds(0,0,300,200); setVisible(true); validate();

addWindowListener(new WindowAdapter()

{ public void windowClosing(WindowEvent e) { System.exit(0); } } ); }

public void actionPerformed(ActionEvent e) { try{ first.start(); second.start();

}

catch(Exception exp){} }

public void run() { while(true)

{ if(【补充代码】) //判断当前占有CPU资源的线程是否是first { moveComponent(redButton); try{ Thread.sleep(20); }

catch(Exception exp){} }

if(【补充代码】) //判断当前占有CPU资源的线程是否是second { moveComponent(greenButton); try{ Thread.sleep(10); }

catch(Exception exp){} } } }

public synchronized void moveComponent(Component b) {

if(Thread.currentThread()==first)

{ while(distance>100&&distance<=200) try{ wait(); }

catch(Exception exp){} distance=distance+1;

b.setLocation(distance,60); if(distance>=100)

{ b.setLocation(10,60); notifyAll(); } }

if(Thread.currentThread()==second)

{ while(distance>=10&&distance<100) try{ wait(); }

catch(Exception exp){} distance=distance+1;

b.setLocation(distance,60); if(distance>200) { distance=10;

b.setLocation(100,60); notifyAll();

} } } }

MoveButtonMainClass.java

public class MoveButtonMainClass

{ public static void main(String args[]) { new MoveButton(); } } 答案: MoveButton.java import java.awt.*; import java.awt.event.*; public class MoveButton extends Frame implements Runnable,ActionListener { /** * */ private static final long serialVersionUID = 1L; Thread first,second; //用Thread类声明first,second两个线程对象 Button redButton,greenButton,startButton; int distance=10; MoveButton() { first=new Thread(this); //创建first线程,当前窗口做为该线程的目标对象 second=new Thread(this); //创建first线程,当前窗口做为该线程的目标对象 redButton=new Button(); greenButton=new Button(); redButton.setBackground(Color.red); greenButton.setBackground(Color.green); startButton=new Button(\); startButton.addActionListener(this); setLayout(null); add(redButton); redButton.setBounds(10,60,15,15); add(greenButton); greenButton.setBounds(100,60,15,15); add(startButton); startButton.setBounds(10,100,30,30); setBounds(0,0,300,200); setVisible(true); validate(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); } public void actionPerformed(ActionEvent e) { try{ first.start(); second.start(); } catch(Exception exp){} } public void run() { while(true) { if(Thread.currentThread()==first) //判断当前占有CPU资源的线程是否是first { moveComponent(redButton); try{ Thread.sleep(20); } catch(Exception exp){} } if(Thread.currentThread()==second) //判断当前占有CPU资源的线程是否是second { moveComponent(greenButton); try{ Thread.sleep(10); } catch(Exception exp){} } } } public synchronized void moveComponent(Component b) { if(Thread.currentThread()==first) { while(distance>100&&distance<=200) try{ wait(); } catch(Exception exp){} distance=distance+1; b.setLocation(distance,60); if(distance>=100) { b.setLocation(10,60); notifyAll(); } } if(Thread.currentThread()==second) { while(distance>=10&&distance<100) try{ wait(); } catch(Exception exp){} distance=distance+1; b.setLocation(distance,60); if(distance>200) { distance=10; b.setLocation(100,60); notifyAll(); } } } } MoveButtonMainClass.java public class MoveButtonMainClass { public static void main(String args[]) { new MoveButton(); } }

练习:在MoveButton类中再增加一个蓝色的按钮和一个third线程,third线程负责将这个蓝色的按钮从(200,60)运动到(300,60)。 MoveButton.java import java.awt.*; import java.awt.event.*; public class MoveButton extends Frame implements Runnable,ActionListener { /** * */ private static final long serialVersionUID = 1L; Thread first,second,third;//【补充代码】 //用Thread类声明first,second两个线程对象 Button redButton,greenButton,blueButton,startButton; int distance=10; MoveButton() { first=new Thread(this);//【补充代码】 //创建first线程,当前窗口做为该线程的目标对象 second=new Thread(this);//【补充代码】 //创建first线程,当前窗口做为该线程的目标对象 third=new Thread(this); redButton=new Button(); greenButton=new Button(); blueButton=new Button(); redButton.setBackground(Color.red); greenButton.setBackground(Color.green); blueButton.setBackground(Color.blue); startButton=new Button(\); startButton.addActionListener(this); setLayout(null); add(redButton); redButton.setBounds(10,60,15,15); add(greenButton); greenButton.setBounds(100,60,15,15); add(blueButton); blueButton.setBounds(200,60, 15, 15); add(startButton); startButton.setBounds(10,100,30,30); setBounds(0,0,350,200); setVisible(true); validate(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); } public void actionPerformed(ActionEvent e) { try{ first.start(); second.start(); third.start(); } catch(Exception exp){} } public void run() { while(true) { if(Thread.currentThread()==first) //判断当前占有CPU资源的线程是否是first { moveComponent(redButton); try{ Thread.sleep(20); } catch(Exception exp){} } if(Thread.currentThread()==second) //判断当前占有CPU资源的线程是否是second { moveComponent(greenButton); try{ Thread.sleep(10); } catch(Exception exp){} } if(Thread.currentThread()==third) { moveComponent(blueButton); try{Thread.sleep(50); } catch(Exception exp){} } } } public synchronized void moveComponent(Component b) { if(Thread.currentThread()==first) { while(distance>100&&distance<=300) try{ wait(); } catch(Exception exp){} distance=distance+1; b.setLocation(distance,60); if(distance>=100) { b.setLocation(10,60); notifyAll(); } } if(Thread.currentThread()==second) { while(distance>=10&&distance<100) try{ wait(); } catch(Exception exp){} distance=distance+1; b.setLocation(distance,60); if(distance>200) { //distance=10; b.setLocation(100,60); notifyAll(); } } if(Thread.currentThread()==third) { while(distance>=10&&distance<200) try{ wait(); } catch(Exception exp){} distance=distance+1; b.setLocation(distance, 60); if(distance>300) {distance=10; b.setLocation(200, 60); notifyAll(); } } } } MoveButtonMainClass.java public class MoveButtonMainClass { public static void main(String args[]) { new MoveButton(); } }

3. 线程的控制

编写一个程序,动画显示文本域中的字符串。

1) 阅读并分析以下程序,将程序中的代码补充完整,编译并运行程序,查看结果。 import java.awt.BorderLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextArea;

import javax.swing.border.BevelBorder;

public class RunnableDemo extends JFrame implements Runnable { // 动画显示的文本字符串

private String introduction = \现在大家已经对计算机很熟悉了,如今计算机的操作\

+ \系统可以同时执行多个任务,在听歌的同时能够打字、下载文件,在聊天窗口打\ + \字的时候,对方同时还能通过视频看到你;听到你。这一切都是使用多任务实现\ + \的,Java语言使用多线程实现一个程序中的多个任务同时运行。程序员可以在程\ + \序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机\ + \制被称为多线程。\;

JTextArea textArea; // 文本域组件 JLabel label; Thread thread;

public RunnableDemo() { setTitle(\线程的控制\);

label = new JLabel(\多线程简介:\); // 标签组件

getContentPane().add(label, BorderLayout.NORTH);// 添加标签到窗体

textArea = new JTextArea(\); // 初始化文本域组件 textArea.setBorder(new BevelBorder(BevelBorder.LOWERED));// 设置边框 textArea.setLineWrap(true); // 设置自动折行

getContentPane().add(textArea, BorderLayout.CENTER);// 添加文本域组件到文本框

setBounds(100, 100, 383, 225); // 设置窗体大小位置 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); // 显示窗体

【补充代码】 //创建thread线程,当前窗口做为该线程的目标对象 【补充代码】 //启动thread线程 }

//Runnable接口方法,是线程的执行方法 @Override

public void run() {

String[] intros = introduction.split(\); // 将字符串分割为数组 for (String ch : intros) { // ForEach遍历字符串数组 textArea.append(ch); // 添加一个字符到文本域 try {

【补充代码】 // 线程休眠0.1秒

} catch (InterruptedException e) { e.printStackTrace(); } } }

public static void main(String args[]) { new RunnableDemo(); // 创建本类实例对象 } }

import java.awt.BorderLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextArea; import javax.swing.border.BevelBorder; //import javax.swing.plaf.SliderUI; public class RunnableDemo extends JFrame implements Runnable { /** * */ private static final long serialVersionUID = 1L; // 动画显示的文本字符串 private String introduction = \现在大家已经对计算机很熟悉了,如今计算机的操作\ + \系统可以同时执行多个任务,在听歌的同时能够打字、下载文件,在聊天窗口打\ + \字的时候,对方同时还能通过视频看到你;听到你。这一切都是使用多任务实现\ + \的,Java语言使用多线程实现一个程序中的多个任务同时运行。程序员可以在程\ + \序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机\ + \制被称为多线程。\; JTextArea textArea; // 文本域组件 JLabel label; Thread thread; public RunnableDemo() { setTitle(\线程的控制\); label = new JLabel(\多线程简介:\); // 标签组件 getContentPane().add(label, BorderLayout.NORTH);// 添加标签到窗体 textArea = new JTextArea(\); // 初始化文本域组件 textArea.setBorder(new BevelBorder(BevelBorder.LOWERED));// 设置边框 textArea.setLineWrap(true); // 设置自动折行 getContentPane().add(textArea, BorderLayout.CENTER);// 添加文本域组件到文本框 setBounds(100, 100, 383, 225); // 设置窗体大小位置 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); // 显示窗体 Thread thread = new Thread(this);//【补充代码】 //创建thread线程,当前窗口做为该线程的目标对象 thread.start();//【补充代码】 //启动thread线程 } //Runnable接口方法,是线程的执行方法 @Override public void run() { String[] intros = introduction.split(\); // 将字符串分割为数组 for (String ch : intros) { // ForEach遍历字符串数组 textArea.append(ch); // 添加一个字符到文本域 try { Thread.sleep(100);//【补充代码】 // 线程休眠0.1秒 } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String args[]) { new RunnableDemo(); // 创建本类实例对象 } }

2) 在窗体的南面添加三个按钮,为程序添加线程控制功能,要求点击开始按钮(startBtn),线程

开始启动,文字逐个显示,并且将按钮状态改变为禁用(因为线程不能重复启动);点击暂停按钮(pauseBtn),线程暂停,文字显示停止;点击恢复按钮(resumeBtn),线程恢复运行,文字继续显示。当线程执行完毕后,恢复开始按钮的状态为可用。程序运行界面如下图所示:

import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.BevelBorder; public class RunnableDemo extends JFrame implements Runnable,ActionListener { private static final long serialVersionUID = 1L; // 动画显示的文本字符串 private String introduction = \现在大家已经对计算机很熟悉了,如今计算机的操作\ + \系统可以同时执行多个任务,在听歌的同时能够打字、下载文件,在聊天窗口打\ + \字的时候,对方同时还能通过视频看到你;听到你。这一切都是使用多任务实现\ + \的,Java语言使用多线程实现一个程序中的多个任务同时运行。程序员可以在程\ + \序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机\ + \制被称为多线程。\; JTextArea textArea; // 文本域组件 JLabel label; Thread thread; JButton startBtn,pauseBtn,resumeBtn; boolean allow=false; public RunnableDemo() { setTitle(\线程的控制\); label = new JLabel(\多线程简介:\); // 标签组件 getContentPane().add(label, BorderLayout.NORTH);// 添加标签到窗体 textArea = new JTextArea(\); // 初始化文本域组件 textArea.setBorder(new BevelBorder(BevelBorder.LOWERED));// 设置边框 textArea.setLineWrap(true); // 设置自动折行 框 textArea.setEditable(false);// 设置不可被编辑 getContentPane().add(textArea, BorderLayout.CENTER);// 添加文本域组件到文本 startBtn=new JButton(\开始\); pauseBtn=new JButton(\暂停\); resumeBtn=new JButton(\恢复\); startBtn.addActionListener(this); pauseBtn.addActionListener(this); resumeBtn.addActionListener(this); JPanel panel=new JPanel(); panel.add(startBtn); panel.add(pauseBtn); panel.add(resumeBtn); getContentPane().add(panel,BorderLayout.SOUTH); setBounds(100, 100, 383, 225); // 设置窗体大小位置 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); // 显示窗体 //setLocationRelativeTo(null);//在屏幕中央显示 } //Runnable接口方法,是线程的执行方法 @Override public void run() { String[] intros = introduction.split(\); // 将字符串分割为数组 for (String ch : intros) { // ForEach遍历字符串数组 synchronized (this) { while(allow){ } } try{ wait(); }catch(InterruptedException e){ e.printStackTrace(); } textArea.append(ch); // 添加一个字符到文本域 try { Thread.sleep(100);//【补充代码】 // 线程休眠0.1秒 } catch (InterruptedException e) { e.printStackTrace(); } } startBtn.setEnabled(true); } public static void main(String args[]) { new RunnableDemo(); // 创建本类实例对象 } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==startBtn){ textArea.setText(\); Thread thread = new Thread(this);//【补充代码】 //创建thread线程,当前窗口做为该线程的目标对象 thread.start();//【补充代码】 //启动thread线程 startBtn.setEnabled(false); }else if(e.getSource()==pauseBtn){ allow=true; }else if(e.getSource()==resumeBtn){ allow=false; synchronized(this){ notifyAll(); } } } }

实验总结

请书写你对本次实验有哪些实质性的收获和体会,以及对本次实验有何良好的建议?

参考文献:

1. 《Java2实用教程(第三版)》耿祥义、张跃平编著,清华大学出版社。

2.《Java2实用教程(第三版)实验指导与习题解答》耿祥义、张跃平编著,清华大学出版社。 3.《Java开发实战宝典》,李钟尉等编著,清华大学出版社。

附录一 Java Code之多态

通过一个简单的例子理解多态的概念 /**

* 人民警察 */

public interface IPolice { /**

* 抓小偷 */

public void catchThief(); }

/**

* 一个警察,执行抓小偷任务. */

public class PoliceReal implements IPolice { public void catchThief() {

System.out.println(\抓住小偷了\); } } /**

* 另一个警察,也执行抓小偷任务. */

public class PoliceHyp implements IPolice { public void catchThief() {

System.out.println(\大冷天的抓什么小偷啊,不如偷个菜.\); } } /** * 市民 */

public class Citizen { private String mName;

public Citizen(String name) { mName = name; } /**

* 市民报案 */

public void report(IPolice police) {

System.out.println(String.format(\市民%s丢失手机,向警察报案抓小偷.\, mName));

police.catchThief(); } }

案情:

市民虽然向警察报了案,

但你不知道能不能把小偷抓住,

甚至你都不知道他们有没有去抓小偷,

还有可能你在电影里看到的剧情真的发生了... 事情经过可能是这样: public class Main {

public static void main(String[] args) { Citizen citizen = new Citizen(\张三\); IPolice police = getPolice(); citizen.report(police); }

private static IPolice getPolice() { return new PoliceReal(); } }

事情结果一:

市民张三丢失手机,向警察报案抓小偷. 抓住小偷了

事情经过也可能是这样: public class Main {

public static void main(String[] args) { Citizen citizen = new Citizen(\张三\); IPolice police = getPolice(); citizen.report(police); }

private static IPolice getPolice() { return new PoliceHyp(); } }

事情结果二:

市民张三丢失手机,向警察报案抓小偷. 大冷天的抓什么小偷啊,不如偷个菜.

事情经过还可能是这样: public class Main {

public static void main(String[] args) { Citizen citizen = new Citizen(\张三\);

IPolice police = getPolice(); citizen.report(police); }

private static IPolice getPolice() { return new PoliceReal() { @Override

public void catchThief() {

System.out.println(\抓小偷?笑话,抓了小偷我哪儿收保护费去啊.\);

} }; } }

事情结果三:

市民张三丢失手机,向警察报案抓小偷.

抓小偷?笑话,抓了小偷我哪儿收保护费去啊.

附录二 内部类的用法

public class China {

final String nationAnthem = \义勇军进行曲\; //内部类声明的对象,作为外嵌类的成员 Beijing beijing; China() {

beijing = new Beijing(); }

String getSong(){

return nationAnthem; }

//内部类的声明 class Beijing{

String name=\北京\; void speak(){

System.out.println(\我们是:\ + name + \我们的国歌是:\ + getSong()); } }

public static void main(String[] args) { China china = new China(); china.beijing.speak(); } }

附录三 和类有关的匿名类

class Cubic{

double getCubic(int n){ return 0; } }

abstract class Sqrt{

public abstract double getSqrt(int x); }

class A{

void f(Cubic cubic){

//执行匿名类体中重写的getCubic

double result = cubic.getCubic(3); System.out.println(result); } }

public class anonymousClass {

public static void main(String[] args) { A a = new A();

//使用匿名类创建对象,将该对象传递给方法f的参数cubic a.f(new Cubic(){ @Override

double getCubic(int n) { return n*n*n; } });

//使用匿名类创建对象,ss是该对象的上转型对象

//匿名类是abstract类Sqrt的一个子类,所以必须要实现getSqrt方法 Sqrt ss = new Sqrt() { @Override

public double getSqrt(int x) { return Math.sqrt(x); } };

//上转型对象调用子类重写的方法 double m = ss.getSqrt(5); System.out.println(m); } }

附录四 和接口有关的匿名类

interface Cubic{

double getCubic(int n); }

interface Sqrt{

public double getSqrt(int x); }

class A{

void f(Cubic cubic){

//执行匿名类体中实现的getCubic

double result = cubic.getCubic(3); System.out.println(result); } }

public class anonymousClass {

public static void main(String[] args) { A a = new A();

//使用匿名类创建对象,将该对象传递给方法f的参数cubic a.f(new Cubic(){

public double getCubic(int n) { return n*n*n; } });

//使用匿名类创建对象,接口ss存放该对象的引用

//匿名类是实现Sqrt接口的类,所以必须要实现getSqrt方法 Sqrt ss = new Sqrt() { public double getSqrt(int x) { return Math.sqrt(x); } };

//接口回调类实现的方法

double m = ss.getSqrt(5); System.out.println(m); } }