我有一个带有四个文本框的GUI窗口,我的代码允许用户创建多个线程。我想为每个线程,线程找到一个可用的文本区域并完成其输出语句。我设法一次只能执行一个线程,但问题是线程访问所有文本区域并写入它们。
用Java编写如下代码:
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
class thread_action extends Thread
{
private semaphores view;
public thread_action(int threadNumber, semaphores view)
{
super(" " + threadNumber);
this.view = view;
}
public void land()
{
//Try to land on Runway 1
synchronized(view.output1) {
view.output1.append("Plane" + getName() + " approach runway.\n");
try { Thread.sleep (2500); }
catch ( InterruptedException e ) {}
view.output1.append("Plane" + getName() + " descending ...\n");
try { Thread.sleep (2500); }
catch ( InterruptedException e ) { }
view.output1.append("Plane" + getName() + " clearing runway and taxi to apron.\n\n");
}
//Landing completed
//Try to land on Runway 2
synchronized(view.output2) {
view.output2.append("Plane" + getName() + " approach runway.\n");
try { Thread.sleep (1000); }
catch ( InterruptedException e ) { }
view.output2.append("Plane" + getName() + " descending ...\n");
try { Thread.sleep (1000); }
catch ( InterruptedException e ) { }
view.output2.append("Plane" + getName() + " clearing runway and taxi to apron.\n\n");
}
//Landing completed
//Try to land on Runway 3
synchronized(view.output3) {
view.output3.append("Plane" + getName() + " approach runway.\n");
try { Thread.sleep (1000); }
catch ( InterruptedException e ) { }
view.output3.append("Plane" + getName() + " descending ...\n");
try { Thread.sleep (1000); }
catch ( InterruptedException e ) { }
view.output3.append("Plane" + getName() + " clearing runway and taxi to apron.\n\n");
}
//Landing completed
//Try to land on Runway 4
synchronized(view.output4) {
view.output4.append("Plane" + getName() + " approach runway.\n");
try { Thread.sleep (1000); }
catch ( InterruptedException e ) { }
view.output4.append("Plane" + getName() + " descending ...\n");
try { Thread.sleep (1000); }
catch ( InterruptedException e ) { }
view.output4.append("Plane" + getName() + " clearing runway and taxi to apron.\n\n");
}
//Landing completed
}
public void run()
{
Random rand = new Random();
int pickedNumber = rand.nextInt(10);
int updateInterval = 1000*pickedNumber;
try { Thread.sleep (updateInterval); }
catch ( InterruptedException e ) {}
view.status.append("Plane:" + getName() + " has entered the airspace.\n");
long start_time = System.currentTimeMillis();
land();
long end_time = System.currentTimeMillis();
long run_time = (end_time - start_time)/1000;
view.status.append("\tPlane" + getName() + " took " + run_time +" seconds to land.\n");
}
}
public class semaphores extends Frame implements ActionListener
{
private static final int WINDOW_HEIGHT = 700;
private static final int WINDOW_WIDTH = 1000;
private Label labelOne, labelTwo, runway1, runway2, runway3, runway4;
private TextField inputOne;
private Button runButton, quitButton;
public static TextArea status, output1, output2, output3, output4;
public semaphores()
{
setTitle("Airport Simulation");
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setResizable(false);
setLocation(10,20);
setLayout(null);
labelOne = new Label("Number of Airplanes:");
labelOne.setBounds(5,17,140,40);
add(labelOne);
inputOne = new TextField();
inputOne.setBounds(150,25,135,25);
add(inputOne);
inputOne.addActionListener(this);
runButton = new Button("Run Program");
runButton.setBounds(5,60,100,25);
add(runButton);
runButton.addActionListener(this);
quitButton = new Button("Quit Program");
quitButton.setBounds(150,60,100,25);
add(quitButton);
quitButton.addActionListener(this);
labelTwo = new Label("Planes Status:");
labelTwo.setBounds(300,20,140,20);
add(labelTwo);
status = new TextArea(10,40);
status.setBounds(300,45,650, 180);
add(status);
runway1 = new Label("Runway 1:");
runway1.setBounds(10,240,140,20);
add(runway1);
output1 = new TextArea(10,40);
output1.setBounds(10,260,450, 200);
add(output1);
runway2 = new Label("Runway 2:");
runway2.setBounds(500,240,140,20);
add(runway2);
output2 = new TextArea(10,40);
output2.setBounds(500,260,450, 200);
add(output2);
runway3 = new Label("Runway 3:");
runway3.setBounds(10,470,140,20);
add(runway3);
output3 = new TextArea(10,40);
output3.setBounds(10,490,450, 200);
add(output3);
runway4 = new Label("Runway 4:");
runway4.setBounds(500,470,140,20);
add(runway4);
output4 = new TextArea(10,40);
output4.setBounds(500,490,450, 200);
add(output4);
}
public void actionPerformed(ActionEvent event)
{
int numThreads;
String getInput;
Button clickedButton = (Button) event.getSource();
if(clickedButton == runButton)
{
status.setText("");
output1.setText("");
output2.setText("");
output3.setText("");
output4.setText("");
getInput = inputOne.getText();
numThreads = Integer.parseInt(getInput);
thread_action[] threads = new thread_action[numThreads];
for(int x=0; x<numThreads; x++)
{
threads[x] = new thread_action(x, this);
}
for(int x=0; x<numThreads; x++)
{
threads[x].start();
}
}
else
{
System.exit(0);
}
}
public static void main(String[] args)
{
semaphores threadObj = new semaphores();
threadObj.setVisible(true);
}
}
答案 0 :(得分:0)
同步呼叫并不意味着“如果跑道1可用则执行此操作”。这意味着“等到跑道1可用然后这样做”。
为此你应该使用标志和锁:
if (runway1available) {
synchronized(runway1) {
runway1available=false;
landonrunway1()
runway1available=true;
}
}
else if (runway2available) {
// ...
}
这样,其他线程可以看到标志已设置,而不是尝试获取锁。检查关键部分内的标志也是更可靠的(双重检查锁定),但在这种情况下将其遗漏没有重大后果。
您还需要小心选择锁定对象 - 在大多数情况下,最好使用您知道不会更改或从其他线程访问的专用锁定对象。