资源描述
实验七 线程
云南大学信息学院 面向对象技术导论 java程序设计大学教程 实验
【开发语言及实现平台或实验环境】
Windows2000 或XP,JDK1.6与Jcreator4.0
【实验目的】
1. 理解线程的基本概念、优先级、生命周期等。
2. 掌握线程的一般创建与使用方法(Thread类与Runnable接口)。
3. 了解线程间的通信、多线程的同步等编程机制。
【实验要求】
1. 运行上课讲解的例子;
2. 完成下列实验内容。
【实验内容】
一、读懂并执行下列程序,理解Java中的多线程机制。
1. 运行下面的程序,理解用创建Thread子类的方法实现多线程。
class SimpleThread extends Thread {
public SimpleThread(String str) {
super(str);
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}
public class TwoThreadsTest {
public static void main (String[] args) {
new SimpleThread("Go to Beijing ").start();
new SimpleThread("Stay here!!").start();
}
}
问题:
(1) 程序的运行结果和功能分别是什么?
(2) 如果程序中去掉try-catch语句,程序是否仍能正常运行?
(3) Thread子类是如何实现多线程机制的?
(4) 如果希望执行三个线程,再显示“Go to Shanghai ”,程序如何修改?比较显示次序,是否相同。为什么会有这样的现象?
答:
1:运行结果:
功能:创建两个线程并打印做检测
2:去掉后程序能够正常运行但是运行的速度加快,即线程没有了等待时间。
3:在编写复杂程序时相关的类可能已经继承了某个基类,而Java不支持多继承,在这种情况下,便需要通过实现Runnable接口来生成多线程
用到Thread类的构造方法
public Thread(Runnable target);
//构造一个新的线程对象,以一个实现Runnable接口的类的对象为参数。默认名为Thread-n,n是从0开始递增的整数。
4:首先在函数TwoThreadsTest添加一个线程即是添加语句new SimpleThread("Go to Qinghai ").start();和System.out.println(“Go to Shanghai”);即可由于学校的机器是四核的无法完成下面的操作!
2. 运行下面的程序,理解用实现Runnable接口的方法实现多线程。
//这是一个时钟Applet,它显示当前时间并逐秒进行更新。
import java.awt.*;
import java.applet.*;
import java.util.*;
public class Clock extends Applet implements Runnable{
Thread clockThread;
public void start(){
if(clockThread==null){
clockThread=new Thread(this,"Clock");
clockThread.start();
}
}
public void run(){
while(clockThread !=null){
repaint();
try{
clockThread.sleep(1000);
}catch(InterruptedException e){}
}
}
public void paint(Graphics g){
Date now=new Date();
g.drawString(now.getHours()+";"+now.getMinutes()+";"
+now.getSeconds(),5,10);
}
public void stop(){
clockThread.stop();
clockThread=null;
}
}
问题:
(1) 在什么情况下一般要通过实现runnable接口实现线程机制?
(2) 程序的运行结果和功能分别是什么?
(3) Runnable接口是如何实现多线程机制的?
(4) 程序中是通过什么方法如何实现逐秒更新显示时间的?
答:(1)在编写复杂程序时相关的类可能已经继承了某个基类,而Java不支持多继承,在这种情况下,便需要通过实现Runnable接口来生成多线程
(2) 结果:
功能:该程序是一个时钟Applet,它显示当前时间并逐秒进行更新。
(3)定义一个实现java.lang.Runnable接口的类,并在该类中定义Runnable接口的run()方法,同样,该run()方法是线程执行的起点。
(4)程序通过调用clockThread.sleep()方法通过控改变sleep()里面的内容来实现逐秒更新显示时间。
3. 运行下面的程序,理解线程的同步。
//程序使用同步块
class Callme{
void call(String msg){
System.out.print("[" + msg );
try{
Thread.sleep(1000);
} catch (InterruptedException e){
System.out.println("Interrupted");
}
System.out.println("]");
}
}
class Caller implements Runnable{
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s){
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
//同步调用call()方法
public void run(){
synchronized(target){//同步块
target.call(msg);
}
}
}
class Java2{
public static void main(String args[]){
Callme target = new Callme();
Caller ob1 = new Caller(target,"Hello");
Caller ob2 = new Caller(target,"Synchronized");
Caller ob3 = new Caller(target,"World");
//等待线程结束
try{
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}
问题:
(1) 程序的运行结果和功能分别是什么?
(2) 程序中如何实现线程的同步?
(3) 去掉程序中的synchronized关键字,运行结果如何?
答:
1:运行结果
功能:创建三个线程,检测线程同步。
2 碰到多个线程对同一资源进行访问的情况,这时,就需要协调: 每个对象都只有一个“锁”与之相连,利用多线程对其的争夺可实现线程间的互斥操作。
当线程A获得了一个对象的锁后,线程B必须等待线程A完成规定的操作、并释放出锁后,才能获得该对象的锁,并执行线程B中的操作。
利用synchronized首先判断对象的锁是否在,如果在就获得锁,然后就可以执行紧随其后的代码段;如果对象的锁不在(已被其他线程拿走),就进入等待状态,直到获得锁
3:去掉关键字后无运行结果。运行结果为空,三个线程均不被执行。
4. 运行下面的程序,理解线程间的通信。
import java.lang.Runnable;
import java.lang.Thread;
public class DemoThread1 implements Runnable{
public DemoThread1() {
TestThread testthread1 = new TestThread(this,"1");
TestThread testthread2 = new TestThread(this,"2");
testthread2.start();
testthread1.start();
}
public static void main(String[] args) {
DemoThread1 demoThread1 = new DemoThread1();
}
public void run(){
TestThread t = (TestThread) Thread.currentThread();
try{
if (!t.getName().equalsIgnoreCase("1")) {
synchronized(this) { wait();}
}
while(true){
System.out.println("@thread"+ t.getName()+ "="+ t.increaseTime());
if(t.getTime()%10 == 0)
{ synchronized(this)
{ System.out.println("*********change thread**********");
this.notifyAll();
if ( t.getTime()==20 ) break;
wait();
}
}
}
}catch(Exception e){e.printStackTrace();}
}
}
class TestThread extends Thread{
private int time = 0 ;
public TestThread(Runnable r,String name){
super(r,name);
}
public int getTime(){
return time;
}
public int increaseTime (){
return ++time;
}
}
问题:
(1) 程序的运行结果和功能分别是什么?
(2) 程序是如何实现线程通信的?可否通过其他方法进行线程间的通信?
(3) 程序中如果去掉notify();语句,程序运行结果会怎样?为什么?
(4) synchronized(this);语句的作用是什么?如果去掉此语句,能否实现线程间的通信?为什么?
答:
(1)程序结果:
功能:创建两个线程并notify();方法和synchronized 关键词,实现线程的同步
(2)程序是通过使用java.lang.Object 类的wait()方法为线程间的通讯提供了有效手段。可以调用notify或notifyAll方法来实现。
(3)
程序结果:
理由:在实际的多线程编程中,会碰到多个线程对同一资源进行访问的情况,这时,就需要协调,这种协调机制实现线程的同步,而notify();语句就是唤醒一个等待的线程,本线程继续执行来实现线程的同步。
(4)synchronized(this);语句的作用是:首先判断对象的锁是否在,如果在就获得锁,然后就可以执行紧随其后的代码段;如果对象的锁不在(已被其他线程拿走),就进入等待状态,直到获得锁。如果去掉此语句,不能实现线程间的通信。理由:会碰到程序中两个线程对同一资源进行访问的情况,去掉此语句该线程无法获得锁,从而进入等待状态,是程序出现异常。
二、编写下列程序。
模拟一个电子时钟,它可以在任何时候被启动或停止,并可独立运行。这个类称为Clock类,它继承Label类。Label类有一个Thread类型的clock域,以及start()、stop()和run()方法。在run()方法的while循环中,每隔1秒就把系统时间显示在label文本。构造方法初始化时,把label设为系统的当前时间。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.*;
public class Main extends JFrame {
Clock clock1,clock2;
public Main()
{
clock1=new Clock();
clock2=new Clock();
this.add(clock1);
this.add(clock2);
this.setBounds(100, 100, 400, 400);
this.setLayout(new FlowLayout());
this.setVisible(true);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) {
Main f=new Main();
}
}
class Clock extends JPanel implements ActionListener, Runnable {
private JTextField abc = new JTextField(20);
Thread t;
private boolean pause = false;
private JButton a = new JButton("暂停");
private long time1 = System.currentTimeMillis();
Clock() {
a.addActionListener(this);
this.add(abc);
this.add(a);
t=new Thread(this);
t.start();
}
public void actionPerformed(ActionEvent e) {
pause = !pause;
if (!pause)
a.setText("暂停");
else
a.setText("开始");
}
public void run() {
while (true) {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
}
if (!pause) {
time1 = time1 + 1000;
Date dtTime = new Date(time1);
abc.setText(dtTime.toString());
}
}
}
}
实验结果 :
展开阅读全文