我一直在研究这个问题,并且无法弄清楚为什么这个applet无法正常工作:
我在applet中实例化了两个线程。 我创建了两个按钮 - 开始和停止,它们应该更改标志值以结束我的线程中的while()循环。小程序没有响应任何一个按钮。任何建议,任何人?谢谢你的时间!
这是小程序......
package prodcons;
import java.applet.Applet;
import java.util.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MyTableSetting extends Applet {
Soup s; // we will show the soup bowl with the soup's alphabet pieces
int bowlLength = 150; // bowl's dimensions as variables in case we want to change it
int bowlWidth = 220;
int bowlX = 60;
int bowlY = 10;
Producer p1;
Consumer c1;
public void init(){
setSize(400,200); // make the applet size big enough for our soup bowl
s = new Soup(); // instantiate the Soup
p1 = new Producer(this, s); // declare and instantiate one producer thread - state of NEW
c1 = new Consumer(this, s); // declare and instantiate one consumer thread - state of NEW
p1.start(); // start the producer thread
c1.start(); // start the consumer thread
Button stop = new Button("Stop");
stop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Producer.producerRunning = false;
Consumer.consumerRunning = false;
Soup.clearBuffer();
}
});
add(stop);
Button start = new Button("Start");
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Producer.producerRunning = true;
Consumer.consumerRunning = true;
p1.run();
System.out.println("heyyy");
c1.run();
}
});
add(start);
}
public void paint(Graphics g){ // first we make the bowl and spoon
int x;
int y;
g.setColor(Color.orange);
g.fillOval(bowlX, bowlY, bowlWidth, bowlLength); // the bowl
g.setColor(Color.cyan);
g.fillOval(10, 25, 40, 55); // the spoon
g.fillOval(25, 80, 8, 75);
g.setColor(Color.black); // black outlines for the dinnerware
g.drawOval(10, 25, 40, 55);
g.drawOval(25, 80, 8, 75);
g.drawOval(bowlX,bowlY, bowlWidth, bowlLength);
ArrayList <String> contents = s.getContents(); // get contents of the soup
for (String each: contents){ // individually add each alphabet piece in the soup
x = bowlX + bowlWidth/4 +(int)(Math.random()* (bowlWidth/2)); // put them at random places to mimic stirring
y = bowlY + bowlLength/4 + (int)(Math.random()* (bowlLength/2));
Font bigFont = new Font("Helvetica", Font.BOLD, 20);
g.setFont(bigFont);
g.drawString(each, x, y);
}
}
}
这些是主题:
package prodcons;
class Consumer extends Thread {
private Soup soup;
private MyTableSetting bowlView;
static boolean consumerRunning = true;
public Consumer(MyTableSetting bowl, Soup s) {
bowlView = bowl; // the consumer is given the GUI that will show what is happening
soup = s; // the consumer is given the soup--the monitor
}
public void run() {
System.out.println("consuming: "+consumerRunning);
String c;
try {
while(consumerRunning) { // stop thread when know there are no more coming; here we know there will only be 10
c = soup.eat(); // eat it from the soup
System.out.println("Ate a letter: " + c); // show what happened in Console
bowlView.repaint(); // show it in the bowl
sleep((int)(Math.random() * 3000)); // have consumer sleep a little longer or sometimes we never see the alphabets!
}
} catch (InterruptedException e) {
this.interrupt();
}
}
}
和此:
package prodcons;
class Producer extends Thread {
private Soup soup;
private String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private MyTableSetting bowlView;
static boolean producerRunning = true;
public Producer(MyTableSetting bowl, Soup s) {
bowlView = bowl; // the producer is given the GUI that will show what is happening
soup = s; // the producer is given the soup--the monitor
}
public void run() {
String c;
try {
while (producerRunning) { // only put in 10 things so it will stop
System.out.println("thikns producer != null");
c = String.valueOf(alphabet.charAt((int)(Math.random() * 26))); // randomly pick a number to associate with an alphabet letter
soup.add(c); // add it to the soup
System.out.println("Added " + c + " to the soup."); // show what happened in Console
bowlView.repaint(); // show it in the bowl
sleep((int)(Math.random() * 2000)); // sleep for a while so it is not too fast to see
}
} catch (InterruptedException e) {
this.interrupt();
}
}
}
这是“汤”类:
package prodcons;
import java.util.*;
public class Soup {
private static ArrayList <String> buffer = new ArrayList<String>(); // buffer holds what is in the soup
private int capacity = 6;
public synchronized String eat() { //this method can only be accessed by one thing at a time
while(buffer.isEmpty()){ // cannot eat if nothing is there, so check to see if it is empty
try {
wait(); // if so, we WAIT until someone puts something there
} catch (InterruptedException e) {} // doing so temporarily allows other synchronized methods to run (specifically - add)
} // we will not get out of this while until something is there to eat
String toReturn = buffer.get((int)(Math.random() * buffer.size())); // get a random alphabet in the soup
buffer.remove(toReturn); // remove it so no one else can eat it
buffer.trimToSize(); // reduce the size of the buffer to fit how many pieces are there
notifyAll(); // tell anyone WAITing that we have eaten something and are done
return(toReturn);
}
public synchronized void add(String c) {
while (buffer.size() == capacity) {
try {
wait();
}
catch (InterruptedException e) {}
}
buffer.add(c);
notifyAll();
}
public ArrayList <String> getContents() {
return buffer;
}
public static void clearBuffer() {
buffer.clear();
}
}
非常感谢你!
答案 0 :(得分:0)
您可以从启动按钮的事件处理程序直接在主UI线程上调用Producer和Consumer。这将产生的唯一影响是冻结整个应用程序。那是因为主UI线程完成了所有事情:事件处理,重新绘制等等。只要你坚持下去,就不会有事件处理,重新绘制等等。
你永远不应该在主UI线程上调用任何需要很长时间的东西。
但是,由于您已经在init
方法中启动了线程,因此您无需在动作侦听器中调用run。你删除了这些电话:
Button start = new Button("Start");
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Producer.producerRunning = true;
Consumer.consumerRunning = true;
}
});
此外,你应该制作标志volatile
,否则在另一个线程中可能看不到从一个线程对它们的更改:
volatile static boolean producerRunning = true;
(等)