资源描述
Java语言程序设计试题及答案
第八章多线程
8.1建立线程有哪两种方法?
答:一是继承Thread类声明Thread子类,用Thread子类创建线程对象。二是在类中实 现Runnable接,在类中提供Runnable接的run(方法。无论用哪种方法,都需要java 基础类库中的Thread类及其方法的支持。程序员能控制的关键性工作有两个方面:一是编 写线程的run(方法;二是建立线程实例。
8.2怎样设置线程的优先级?
答:setPriority(in设定线程的优先级为p(1~10)线程创建时,子线程继承父线程的 优先级。
优先级的数值越大优先级越高(缺省为5)。常用以下3个优先级:
Thread.MIN_PRIORITY (最低)
Thread.MAX_PRIORITY (最高)
Thread.NORMAL_PRIORITY (标准)
8.3编写程序,一个画圆,一个画椭圆。
程序运行结果:
Applet 的源文件:Work8_3.java
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
/**
* 8.3用一个红色笔画圆,同时用一个蓝色笔画椭圆
*/
public class Work8_3 extends Applet implements Runnable
private static final long serialVersionUID = 1L;
/**两个线程,红笔线程,和蓝笔线程*/
private Thread red_thread , blue_thread ;
/**红色画笔、蓝色画笔*/
private Graphics redPen , bluePen ;
/**蓝、红笔画时需要旋转角度*/
private int blue_angle = 0, red_angle = 0;
/**红色画的图案的中心坐标*/
private int a_red = 1, b_red = 1;
/**蓝色画的图案的中心坐标*/
private int a_blue = 3, b_blue = 1;
/**圆形半径*/
privateintradius_red=80;
/**椭圆的两个半径*/
privateintradius1_blue= 150,radius2_blue = 1;
publicvoidinit()
{
red_thread = new Thread( this );
blue_thread = new Thread( this );
redPen = getGraphics();
bluePen = getGraphics();
setBackground(Color. white );
setSize(470, 240);
}
public void start()
{
red_thread .start(); // 两个线程开始 blue_thread .start();
}
public void run()
{
while ( true )
{
if (Thread. currentThread () == red_thread )
{
redPen .drawOval(25, 25, 160, 160);// 绘制圆的边框。
x,y,width,height
intx = getX(radius_red,red_angle,a_red );
inty = getY(radius_red,red_angle,b_red );
redPen .setColor(Color. WHITE );
redPen .fillOval(x, y, 10, 10);//用白色画一次,可以擦出痕迹 red_angle += 3;
x = getX(80, y = getY(80, redPen .setColor(Color. redPen .fillOval(x, y, 10,
red_angle
red_angle
if (red_angle >= 360) red_angle = 0;
,1);
, 1);
RED);
10);//使用当前颜色填充外接指定矩
形框的椭圆
try
{
Thread. sleep (10);
)
catch ( InterruptedException e )
{
)
)
else if (Thread. currentThread () == blue_thread )
{
bluePen .drawOval( a_blue / 2 + 5, b_blue / 2 - 45, radius1_blue * 2,
radius2_blue * 2); // 绘制椭圆的边框。x,y,width,height intx = getX(radius1_blue,blue_angle,a_blue );
inty = getY(radius2_blue,blue_angle,b_blue );
bluePen .setColor(Color. WHITE );
bluePen .fillOval(x, y, 10, 10);// 擦除痕迹
blue_angle += 3;
if (blue_angle >= 360) blue_angle = 0;
x = getX( radius1_blue , blue_angle , 3);
y = getY( radius2_blue , blue_angle , 1);
bluePen .setColor(Color. BLUE );
bluePen .fillOval(x, y, 10, 10);// 擦除痕迹
try {
Thread. sleep (20);
)
catch ( InterruptedException e )
{
)
)
)
)
/**
*用参数方程方法,计算坐标的方法
* @param r圆的半径,椭圆的两个半轴
* @param loc x坐标的相对偏移量
* @param angle旋转的角度,单位为角度
* @return 计算后的坐标值
*/
public int getX( int r, int angle,int locX)
{
int x = locX + ( int ) (r * Math.cos (Math. PI / 180.0 * angle));
return x;
)
/**
*用参数方程方法,计算坐标的方法
* @param r圆的半径,椭圆的两个半轴
* @param loc Y坐标的相对偏移量
* @param angle旋转的角度,单位为角度
* @return 计算后的坐标值
*/
public int getY( int r, int angle, int locY)
{
int y = locY + ( int ) (r * Math. sin (Math. PI / 180.0 * angle));
return y;
8.4在多线程程序中,要考虑互斥的原因是什么?在Java中如何解决?
答:多线程之间要共享资源,为了保护资源在使用时,不被其他线程使用。
在Java语言中,使用关键字synchronize定义临界段,能对共享对象的操作上锁。
8.5在多线程程序中,要考虑同步的原因是什么?在Java中如何解决?
答:在临界段中使用wait方法,使执行该方法的线程等待,并允许其他线程使用这个 临界段。wait(方法常用以下两种格式:
wait()让线程一直等待,直到被notify或notifyAll;方)法唤醒。
wait(long timeout)线程等待到被唤醒,或经过指定时间后结束等待。
当线程使用完临界段后,用notify方法通知由于想使用这个临界段而处于等待的线程 结束等待。notify方法只是通知第一个处于等待的线程。如果某个线程在使用完临界段方 法后,其他早先等待的线程都可结束等待,重新竞争CPU,则可以notifyAll为法。
8.6模拟排队买票,球票5元,购票者持有5, 10, 20, 50元的,售票员手里开 始没有零钱。
程序运行结果:
主窗体源文件:BuyTicketFrame.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* 8.6线程实现,购票规则,由于我想的算法太过复杂,只写到50元面值的
* @author 段智敏
*/
public class BuyTicketFrame extends JFrame implements ActionListener,
Runnable {
private static final long serialVersionUID = 1L;
private Conductor lady ;
private int array [] 10, 5, 10, 20, 5 };
( 10, 10, 5, 20, 50, 5, 5, 5, 5, 5, 5, 10, 20,
private private static private private
int number = array . length ;
Thread thread [] = new Thread[ number ];
JTextArea text ;
JPanel panel ;
JButton begin_button , replay_button ;
public BuyTicketFrame()
{
super ("第八章,第六题,线程模拟购票");
lady = new Conductor(15);
text = new JTextArea();
panel = new JPanel();
begin_button = new JButton("开始买票");
replay_button = new JButton("重新开始");
for ( int i = 0; i < array . length ; i++) thread [i] = new Thread( this );
begin_button .addActionListener( this );
replay_button .addActionListener( this );
panel .setLayout( new FlowLayout());
panel .add( begin_button );
panel .add( replay_button );
this .add( panel , BorderLayout. NORTH );
this .add( new JScrollPane( text ), BorderLayout. CENTER );
this .setSize(10, 7);
this .setVisible( true );
this .validate();
this .addWindowListener( new WindowAdapter() // 窗监视器
{
public void windowClosing(WindowEvent e)
{
System. exit (0);
) });
)
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == begin_button )// 线程开始
{
text .setText( "********"+ number + "个人排队买票,共"+
lady .getTicketAmount() +"张票,开始卖票:\n");
try
{
for ( int i = 0; i < array . length ; i++)
{
thread [i].start();
if ( thread [i].isAlive())
text .append( " " + (i + 1) + "线程开始\n");
) begin_button .setForeground(Color. RED);
)
catch ( IllegalThreadStateException ee )
{
text .append( "error :重复启动线程"+ ee.toString());
)
//检查线程是否结束
while ( true )
{
int n = 0;
for ( int i = 0; i < array . length ; i++)
{
if (thread [i].isAlive())
break ;
else
n++;
}
if (n == array . length )
break ;
}
begin_button .setForeground(Color. BLUE); // 全部线程结束
text .append( "\n全部线程结束,已经没有排队等待买票的了");
}
if (e.getSource() == replay_button )
{
this .removeAll();
new BuyTicketFrame();
}
}
public void run()
{
for ( int i = 0; i < array . length ; i++)
{
if (Thread. currentThread () == thread [i]) lady .rule(i + 1, array [i]);
}
}
public static void main(String args[])
{
new BuyTicketFrame();
}
}
售票员类源文件:Conductor.java
/**
*售票员
* @author 段智敏
*/
class Conductor
{
/**售票员开始持有的各种钞票的数量*/
private int five = 0, ten = 0, twenty = 0, fifty = 0;
/**总的票数*/
private int ticket_amount ;
/**
*构造方法
* @param number -票的初始数
*/
public Conductor( int number)
{
this . ticket_amount = number;
}
public int getTicketAmount() {
return ticket_amount
/**
*买票规则方法
*/
public synchronized void rule( int index, int money)
{
if (ticket_amount <= 0)
{
BuyTicketFrame. text .append(index +"************ 售票结束
**********\n");
return ;
)
if (money == 5)
fiveGive(index);
if (money == 10)
tenGive(index);
if (money == 2 0)
twentyGive(index);
if (money == 5 0)
fiftyGive(index);
BuyTicketFrame. text
.append("
"); BuyTicketFrame. text .append("剩余票数:"+ ticket-amount + "张:¥:
5 元:"+ five + "张;10 元:"+ ten
+ "张;20 元:"+ twenty + "张;50 元:"+ fifty + "张\n"); notifyAll(); //唤醒所以线程
public void fiveGive( {
if ( ticket-amount
{
BuyTicketFrame.
**********\n" );
return ;
) else {
five ++;
ticket-amount
BuyTicketFrame. 给你票\n");
)
)
int index)
<= 0)
text .append(index +
************
售票结束
text .append("第"+ index +
"个,5快的,钱正好,
public void tenGive( int index) // 10 元找钱规则
{
while ( true )
{
if (five >= 1)
break ;
else
{
BuyTicketFrame. text .append("第"+ index +"个,10 元,找不 开,发...生...等...待... ☆☆☆☆☆\n");
try
{
wait();
)
catch ( InterruptedException e )
{
)
)
)
if (ticket_amount <= 0)
{
BuyTicketFrame. text .append(index +"************ 售票结束
**********\n");
return ;
)
else
{
ticket_amount 一;
five --;
ten ++;
BuyTicketFrame. text .append("第"+ index +"个,10 元的,找你 5
元的,给你票\n");
)
)
public void twentyGive( int index) // 20 元找钱规则
{
while ( true )
{
if ((( five >= 1 && ten >= 1) || five >= 3)) // 20 元的两种找钱 规则:3*5,10+5
break ; //跳出while循环,意味着有符合的规则
else
{
BuyTicketFrame. text .append("第"+ index +"个,20 元,找不
开,发...生...等...待... ☆☆☆☆☆\n");
try
{
wait();
)
catch ( InterruptedException e )
{
)
)
) if ( ticket_amount <= 0) { BuyTicketFrame. text .append(index +"************ 售票结束
**********\n");
return ;
) else if (ten >= 1 && five >= 1) // 20 元找钱规则:10+5 {
ticket_amount five --;
ten 一;
twenty ++;
BuyTicketFrame. text .append("第"+ index +"个,20 元的,找你 1
个5元,1个10块的,给你票\n");
return ;
}
else if (five >= 3) // 20 元找钱规则:5*3
{
ticket-amount 一;
five -= 3;
twenty ++;
BuyTicketFrame. text .append("第"+ index +"个,20 元的,找你 3
个5元的,给你票\n");
}
}
public void fiftyGive(
int index) // 50元,找钱规则
while (true )
{
five
4 &&
if (( twenty >= 2 && five >= 1) || ( twenty >= 1 && ten >= 2 && >= 1)
|| ( twenty >= 1 &&ten >= 1 &&five >= 3) || ( ten >= five >= 1)
|| ( ten >= 3 &&five >= 3) || ( ten >= 2 &&five >= 5)
|| ( ten >= 1 &&five >= 7) || ( five >= 9))
break ; // 50元的8种找钱方法
else
{
BuyTicketFrame.
text .append(
第"+ index +
”个,50元,找不
开,发...生...等...待... ☆☆☆☆☆\n");
try
{
wait();
}
catch ( InterruptedException e )
{
}
}
}
//跳出while循环后,符合照片规则
if (ticket-amount <= 0)
{
BuyTicketFrame. text .append(index +"************ 售票结束
**********\n");
return ;
}
//先可20的先找,然后在10元的
else if (twenty >= 2 &&five >= 1) // 50 元找钱规则 1: 20*2+5 {
ticket-amount--;
five --;
twenty -= 2;
fifty ++;
BuyTicketFrame. text .append("第"+ index + "个,50 元的,找你 2
个20 , 1个5元的,给你票\n");
return ;
else if (twenty >= 1 &&ten >= 2 && 20+10*2+5
{
ticket_amount 一;
twenty 一;
ten -= 2;
five 一;
fifty ++;
BuyTicketFrame. text .append("第" 个20,2个10,1个5元的,给你票\n");
return ;
)
five >= 1) // 50元找钱规则2:
+ index +"个,50元的,找你1
else if (twenty >= 1 &&ten >= 20+10+5*3
{
ticket_amount一;
twenty --;
ten --;
five -= 3;
fifty ++;
BuyTicketFrame. text .append(
个20,1个10,1个5元的,给你票\n");
return ;
)
else if (ten >= 4 && five >= 1)
{
ticket_amount一;
ten -= 4;
five -= 1;
fifty ++;
BuyTicketFrame. text .append( 个10,1个5元的,给你票\n");
return ;
)
else if (ten >= 3 && five >= 3)
{
ticket_amount一;
ten -= 3;
five -= 3;
fifty ++;
BuyTicketFrame. text .append( 个10,3个5元的,给你票\n");
return ;
)
else if (ten >= 2 &&five >= 5)
{
ticket-amount一;
ten -= 2;
five -= 5;
fifty ++;
BuyTicketFrame. text .append( 个10 , 5个5元的,给你票\n");
return ;
)
else if (ten >= 1 && five >= 7)
{
1 && five >= 3) // 50 元找钱规则 3
"第"+ index +"个,50元的,找你1
// 50元找钱规则4: 10*4+5
"第"+ index +"个,50元的,找你4
// 50元找钱规则5: 10*3+5*3
"第"+ index +"个,50元的,找你3
// 50元找钱规则6: 10*2+5*5
"第"+ index +"个,50元的,找你2
// 50元找钱规则7: 10+5*7
ticket-amount
ten --;
five -= 7;
fifty ++;
BuyTicketFrame. text .append("第"+ index +"个,50 元的,找你 1
个10,7个5元的,给你票\n");
return ;
}
else if (five >= 9) // 50 元找钱规则 8: 5主窗类:MainFrame.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
*排队买票,主窗类
* @author 段智敏
9
{
ticket_amount --;
five -= 9;
fifty ++;
BuyTicketFrame. text .append("第"+ index +"个,50 元的,找你 9
个5元的,给你票\n");
}
}
}
8. 7修改例8.5程序,使一些暂时找不到零钱等待的顾客能按照先来先买的规则, 排队等待购买纪念品。
程序运行结果:
开船植示
货员:顾客-A用1。元买物品,设有雪跋,话去重新排队囚粮无
▲职T,U回吸伍:A*
售货员:顾客七,用1 元买物品,没有孝成,话去重新拌队.Bt&S
日来排阳了,此时阳伍:AB
售货员:顾客。成颜睬1个纪念品,你的跋正好
。来排耿了,此时耿伍内BC
愕货员:顾客。牌蛔买1个纪危品,你始撕映』我携愀块!
—来排耿了,上t时耿伍A日。D
悟货员:顾客叭用1。元买柚品,设有雪犊,话去重新排队囚粮无
碱头|折以去买票并出队| J1L5拟伍:日C D
售货员:顾客七,用1 元买物品,没有孝成,话去重新拌队.Bt&S
确联7,岫瞄日CD A
悟货员:顾客叭用1。元买物品,设有雪跋,话去重新排队囚粮无
日在阳头,所以去买票并出阳,此时限伍: &
售货员:顾客七,用1 元买物品,没有孝成,话去重新拌队.Bt&S
日来排阳了,此时阳来:(3『日
悟货员:顾客叭用1。元买物品,设有雪跋,话去重新排队囚粮无
。在耿头,所以古买票并出耿,此时耿伍。丹日
售货员:顾客七,用1 元买物品,没有孝成,话去重新拌队.Bt&S
在耿头,所以古买票开出耿,此时眈伍内日
悟货员:顾客叭用1。元买物品,设有雪跋,话去重新排队囚粮无
砌&』所以去买票并出队』此5拟伍:日
售货员:顾客七,用1 元买物品,没有孝成,话去重新拌队.Bt&S
确胴。岫愤伍:日A
悟货员:顾客叭用1。元买物品,设有雪跋,话去重新排队囚粮无
日在阳头,所以去买票并出阳,此时限伍:A
售货员:顾客七,用1 元买物品,没有孝成,话去重新拌队.Bt&S
日来排阳了,此时阳伍:A日
悟货员:顾客叭用1。元买物品,设有雪跋,话去重新排队囚粮无
砌&』所以去买票并出队』此5拟伍:日
售蒙员:唳容二用1 元买物品,没有孝成,话去重新拌队Bt&A
▼ 麻排岫祁刷:BA
<1inH
— 7TIU以』区;|?| 土R距甘由以』|注时团怙・皿1二
private int moneies [] = ( 10, 10, 5, 10, 5, 10, 5, 5, 10, 5, 10, 5, 5, 10, 5, 10, 5, 5, 5 };
private Customer[] customer ;
private SalesLadylady ;
/**显示信息的文本区,显示售票员信息,和队伍信息*/
private JTextAreatext1 , text2 ;
/**开始按钮*/
private JButton start_button ;
/**布局用的panel */
private JPanel panel1 , panel2 ;
public MainFrame()
{
super ("多线程-排队-买票");
customer = new Customer[ name . length ];
lady = new SalesLady( name . length );
text1 = new JTextArea();
text2 = new JTextArea();
start-button = new JButton("开始演示");
panel1 = new JPanel();
panel2 = new JPanel();
lady .setJTextArea( text1 , text2 );
start-button .addActionListener(this );
panel1 .setBorder(BorderFactory.createTitledBorder("信息栏"));
panel1 .setLayout( new GridLayout(1, 2, 10, 10));
panel1 .add( new JScrollPane(text1 ));
panel1 .add( new JScrollPane(text2 ));
panel2 .add( start-button );
this .setBounds(50, 50, 550, 4);
this .add( panel1 , BorderLayout.CENTER );
this .add( panel2 , BorderLayout.NORTH );
this .setVisible( true );
this .validate();
this .addWindowListener( new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System. exit (0);
)
});
)
public void actionPerformed(ActionEvent e)
{
start-button .setEnabled( false );
lady .start();
for ( int i = 0; i < name . length ; i++)
{
customer [i] = new Customer( name [i], moneies [i], lady ); // 创 建消费者
customer [i].start();
)
)
public static void main(String args[])
{
new MainFrame();
)
)
售货员类源文件:SalesLady.java
import javax.swing.JTextArea;
/**
*售货员类
*/
public class SalesLady extends Thread
{
private int mem , five , ten ; // 纪念品数,5、10 元 RMB 张数
private LinkQueue queue ; // 链队歹0
private boolean state ; //用来让线程结束的
private JTextArea textl , text2 ;
private int amount ; //用来确定线程的结束
public SalesLady( int length)
{
this . amount = length;
mem = 20;
five = 0;
ten = 0;
state = true ;
queue = new LinkQueue();
)
/**
*构造方法
* @paramm-纪念品数
* @paramf-5 元数量
* @paramt-10 元数量
* @paraml-人数
*/
public SalesLady( int m, int f, int t, int l)
{
this . mem = m;
this . five = f;
this . ten = t;
this . amount = l;
state = true ;
queue = new LinkQueue();
)
/**
*排队,入队列
* @param obj
*/
public synchronized void stand_in_a_line(Object obj)
{
queue .enQueue(obj);
text2 .append(obj.toString() + ”来排队了,此时队伍:”+ queue .printQueue() +"\n");
)
public void run()
{
while ( state )
{
if ( amount == 0) break ;
if (! queue .isEmptyQueue())
{
try
{
Customer cus = (Customer) queue .outQueue();
text2 .append(cus.toString() +"在队头,所以去买票并出队,
此时队伍:"+ queue .printQueue()
+ "\n" );
text1 .append(ruleForSale(cus));
}
catch ( Exception e )
{
e.printStackTrace();
}
}
}
text1 .append("售货员:没人排队了,我下班了");
}
/**
*卖票规则方法
* @param num -顾客号
* @param money -顾客给的钱
* @return -购买信息
*/
public String ruleForSale(Customer cust)
{
String message ="" ;
int money = cust.getMoney();
String name = cust.getCustomerName();
if (mem == 0)
{
state = false ;
message ="售货员:对不起,纪念币已经卖完!\n" ;//结束方法
}
else if (money == 5)
{
mem --;
five ++;
amount --;
message ="售货员:顾客-"+ name +",成功购买1个纪念品,你的钱正
好.\n";
}
else if (money == 10)
{
if (five < 1)
{
stand_in
展开阅读全文