Java 多线程编程 实验二
1.创建键盘操作练习
题目描述:
编写一个Java应用程序,在主线程中再创建两个线程,
一个线程负责给出键盘上字母键上的字母,另一个线程负责让用户在命令行 输入所给出的字符。
(1) 实验运行结果截图:
(2) 代码补充结果为:
【代码1】创建线程 giveChar:giveChar = new GiveLetterThread();
【代码2】创建线程 typeChar:typeChar = new InputLetterThread();
【代码3】调用sleep方法使得线程中断 sleepLength 毫秒: Thread.sleep(sleepLength);
(3) 源码:
TypeKey.java代码:
package Question1;
public class TypeKey {
public static void main(String args[]){
System.out.println("键盘练习(输入#结束程序)");
System.out.println("输入显示的字母(回车)\n");
Letter letter;
letter = new Letter();
GiveLetterThread giveChar;
InputLetterThread typeChar;
giveChar = new GiveLetterThread();
//【代码1】创建线程 giveChar
giveChar.setLetter(letter);
giveChar.setSleepLength(3200);
typeChar = new InputLetterThread();
//【代码2】创建线程 typeChar
typeChar.setLetter(letter);
giveChar.start();
typeChar.run();
}
}
Letter.java代码:
package Question1;
public class Letter {
char c = '\0';
public void setChar(char c){
this.c = c;
}
public char getChar(){
return c;
}
}
GiveLetterThread.java代码:
package Question1;
public class GiveLetterThread extends Thread{
Letter letter;
char startChar = 'a',endChar = 'z';
int sleepLength = 5000;
public void setLetter(Letter letter){
this.letter = letter;
}
public void setSleepLength(int n) {
sleepLength = n;
}
public void run(){
char c = startChar;
while (true){
letter.setChar(c);
System.out.printf("显示的字符: %c\n",letter.getChar());
try{
Thread.sleep(sleepLength);
//【代码3】 //调用sleep方法使得线程中断 sleepLength 毫秒
} catch (InterruptedException e) {}
c = (char)(c+1);
if(c > endChar)
c = startChar;
}
}
}
InputLetterThread.java代码:
package Question1;
import java.util.Scanner;
public class InputLetterThread extends Thread{
Scanner reader;
Letter letter;
int score = 0;
InputLetterThread(){
reader = new Scanner(System.in);
}
public void setLetter(Letter letter) {
this.letter = letter;
}
@Override
public void run() {
while (true){
//System.out.printf("输入显示的字母(回车)\n");
String str = reader.nextLine();
char c = str.charAt(0);
if(c == letter.getChar()){
score++;
System.out.printf("\t\t输入对了,目前分数:%d\n",score);
}
else {
System.out.printf("\t\t输入错了,目前分数:%d\n",score);
}
if(c == '#')
System.exit(0);
}
}
}
2. 双线程猜数字
题目描述:
用两个线程玩猜数字游戏,第一个线程负责随机给出1~10之间的一个整数,第二个线程负责猜出这个数。
要求:每当第二个线程给出自己的猜测后,第一个线程都会提示“猜小了”、“猜 大了”或“猜对了”。猜数之前,要求第二个线程要等待第一个线程设置好 要猜测的数。第一个线程设置好猜测数之后,两个线程还要相互等待,其原 则是:第二个线程给出自己的猜测后,等待第一个线程给出的提示;第一个 线程给出提示后,等待第二个线程给出猜测,如此进行,直到第二个线程给 出正确的猜测后,两个线程进入死亡状态。
(1) 实验运行结果截图:
(2) 代码补充结果为:
【代码1】创建giveNumberThread,当前 Number 类的实例是 giveNumberThread 的目标对象:giveNumberThread = new Thread(this);
【代码2】创建guessNumberThread,当前Number类的实例是 guessNumberThread 的目标对象: guessNumberThread = new Thread(this);
(3) 源码:
TwoThreadGuessNumber.java代码:
package Question2;
public class TwoThreadGuessNumber {
public static void main(String args[]){
Number number = new Number();
number.giveNumberThread.start();
number.guessNumberThread.start();
}
}
Number.java代码:
package Question2;
public class Number implements Runnable{
final int SMALLER = -1,LARGER = 1,SUCCESS = 8;
int realNumber,guessNumber,min = 0,max = 100,message = SMALLER;
boolean pleaseGuess = false,isGiveNumber = false;
Thread giveNumberThread,guessNumberThread;
Number(){
giveNumberThread = new Thread(this);
//【代码1】创建 giveNumberThread,当前 Number 类的实例是 giveNumberThread 的目标对象
guessNumberThread = new Thread(this);
//【代码2】创建 guessNumberThread,当前 Number 类的实例是 guessNumberThread 的目标对象
}
public void run() {
for (int count = 1;true;count++){
setMessage(count);
if(message == SUCCESS)
return;
}
}
public synchronized void setMessage(int count){
if(Thread.currentThread()==giveNumberThread && isGiveNumber==false){
realNumber = (int)(Math.random()*100)+1;
System.out.println("随机给你一个1至100之间的数,猜猜是多少?");
isGiveNumber = true;
pleaseGuess = true;
}
if(Thread.currentThread()==giveNumberThread){
while (pleaseGuess == true)
try {
wait(); //让出 CPU 使用权,让另一个线程开始猜数
}
catch (InterruptedException e){}
if (realNumber > guessNumber){ // 结束等待后,根据另一个线程的猜测给出提示
message = SMALLER;
System.out.println("你猜小了");
}
else if (realNumber < guessNumber){
message = LARGER;
System.out.println("你猜大了");
}
else {
message = SUCCESS;
System.out.println("恭喜,你猜对了");
}
pleaseGuess = true;
}
if(Thread.currentThread() == guessNumberThread && isGiveNumber == true){
while (pleaseGuess == false)
try {
wait(); //让出 CPU 使用权,让另一个线程给出提示
}
catch (InterruptedException e){}
if (message == SMALLER){
min = guessNumber;
guessNumber = (min+max)/2;
System.out.println("我第"+count+"次猜这个数是:"+guessNumber);
}
else if (message == LARGER){
max = guessNumber;
guessNumber = (min+max)/2;
System.out.println("我第"+count+"次猜这个数是:"+guessNumber);
}
pleaseGuess = false;
}
notifyAll();
}
}
3. 月亮围绕地球
题目描述:
编写一个应用程序,模拟月亮围绕地球转。其中月亮和地球为给定图片如下所示:
(1) 实验运行结果截图:
(2) 代码补充结果为:
【代码1】创建 timer,振铃间隔是 20 毫秒,当前 Earth 对象为其监视器:
timer = new Timer(20,this);
【代码2】创建 timer,振铃间隔是100毫秒,当前Sky对象为其监视器:
timer = new Timer(100,this);
(3) 源码:
MainClass.java代码:
package Question3;
import javax.swing.*;
import java.awt.*;
public class MainClass {
public static void main(String args[]){
Sky sky = new Sky(); //构造了一个天空(标签对象)
JFrame frame = new JFrame(); //构造了一个框架(窗体)
frame.add(sky); //将天空(标签)置于框架(窗体)里
frame.setTitle("月亮绕地球转");
frame.setSize(500,500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.white);
}
}
Earth.java代码:
package Question3;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Earth extends JLabel implements ActionListener {
JLabel moon; //显示月亮的外观
Timer timer;
double pointX[] = new double[360],
pointY[] = new double[360];
int w = 200,h = 200,i = 0;
Earth(){
setLayout(new FlowLayout());
setPreferredSize(new Dimension(w,h));
timer = new Timer(20,this);
//【代码1】创建 timer,振铃间隔是 20 毫秒,当前 Earth 对象为其监视器
setIcon(new ImageIcon("earth.jpg"));
setHorizontalAlignment(SwingConstants.CENTER);
moon = new JLabel(new ImageIcon("moon.png"),SwingConstants.CENTER);
add(moon);
moon.setPreferredSize(new Dimension(60,60));
pointX[0] = 0;
pointY[0] = h/2;
double angle = 1*Math.PI/180; //刻度为 1 度
for(int i = 0;i < 359;i++){ //计算出数组中各个元素的值
pointX[i+1] = pointX[i]*Math.cos(angle) - Math.sin(angle)*pointY[i];
pointY[i+1] = pointY[i]*Math.cos(angle) + Math.sin(angle)*pointX[i];
}
for (int i = 0;i < 360;i++){
pointX[i] = 0.8*pointX[i] + w/2; //坐标缩放,平移
pointY[i] = 0.8*pointY[i] + h/2;
}
timer.start();
}
@Override
public void actionPerformed(ActionEvent e) {
i = (i+1)%360;
moon.setLocation((int)pointX[i]-30,(int)pointY[i]-30);
}
}
Sky.java代码:
package Question3;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Sky extends JLabel implements ActionListener {
Earth earth;
Timer timer;
double pointX[] = new double[360],
pointY[] = new double[360];
int w = 400,h = 400,i = 0;
Sky(){
setLayout(new FlowLayout());
timer = new Timer(100,this);
//【代码2】创建 timer,振铃间隔是100毫秒,当前Sky对象为其监视器
setPreferredSize(new Dimension(w,h));
earth = new Earth();
add(earth);
earth.setPreferredSize(new Dimension(200,200));
pointX[0] = 0;
pointY[0] = h/2;
double angle = 1*Math.PI/180; //刻度为 1 度
for(int i = 0;i < 359;i++){ //计算出数组中各个元素的值
pointX[i+1] = pointX[i]*Math.cos(angle) - Math.sin(angle)*pointY[i];
pointY[i+1] = pointY[i]*Math.cos(angle) + Math.sin(angle)*pointX[i];
}
for (int i = 0;i < 360;i++){
pointX[i] = 0.5*pointX[i] + w/2; //坐标缩放,平移
pointY[i] = 0.5*pointY[i] + h/2;
}
timer.start();
}
@Override
public void actionPerformed(ActionEvent e) {
i = (i+1)%360;
earth.setLocation((int)pointX[i]-100,(int)pointY[i]-100);
}
}