我在Java中的线程有问题。我想写一个程序,其中有 Class Main 它有某个类(类任务(的线程数组列表,它只写一个字母和数字。Object Main 只是从 ArrayList 中唤醒一个线程,并让它做一些事情,而同一个对象 (Main( 则让另一个线程休眠。但是有一个问题,即使我将 Main.ACTIVE 更改为 false,它也不会结束一些保留的所有线程,而且它是随机的,我只想让它们结束并写入:
我说的是好湾+性格 - 像那样
public class Main extends Thread {
ArrayList<Thread> threads;
static boolean ACTIVE = true;
public Main() {
super();
threads = new ArrayList<Thread>();
}
public void run(){
Object monitor = new Object();
for (int i = 0; i <= 5; i++) {
threads.add(new Thread(new Task(i + 65, monitor)));
}
long cT = System.currentTimeMillis();
for (int i = 0; i < threads.size(); i++) {
threads.get(i).start();
}
System.out.println("BEFORE synchronized(monitor)");
synchronized(monitor){
while (System.currentTimeMillis() - cT < 1000) {
try{
monitor.notify();
Thread.sleep(50);
monitor.wait();
} catch(Exception e){
e.printStackTrace();}
}
System.out.println("BEFORE ACTIVE= FALSE and after WHILE in Main");
ACTIVE = false;
for(int i = 0; i < threads.size(); i++){
System.out.println(threads.get(i).getState());
}
}
System.out.println("LAST COMMAND IN MAIN");
}
}
public static void main(String[] args) {
new Main().start();
//new Thread(new Task(65)).start();
}
}
和任务类
public class Task implements Runnable {
int nr;
char character;
Object monitor;
public Task(int literaASCII, Object monitor) {
this.nr = 0;
this.monitor = monitor;
character = (char) (literaASCII);
}
@Override
public void run() {
synchronized (monitor) {
while (Main.ACTIVE) {
try {
System.out.println("ENTERING WHILE IN TASK");
monitor.wait();
System.out.print(nr + "" + character + ", ");
nr++;
int r = (int) ((Math.random() * 50) + 50); // <500ms,1000ms)
Thread.sleep(r);
} catch (Exception e) {e.printStackTrace();}
monitor.notify();
System.out.println("YYYYYYYYY");
}
System.out.println("AFTER WHILE IN Task");
}
System.out.println("I am saying goodbye " + character);
}
}
我建议您查看java.util.concurrent
包中更现代的并发类,尤其是ExecutorService
。 并阅读"Java 并发实践"。
您的问题是对于初学者来说,ACTIVE
应该标记为volatile
。 由多个线程共享的任何变量都需要以某种方式synchronized
或标记为volatile
,以便它的读取和写入具有内存屏障。
从布尔的角度来看,您可以做的另一件事是使用 AtomicBoolean
类而不是 volatile boolean
。
而不是static volatile boolean
,您可以考虑为每个Task
对象设置一个volatile boolean
,以便Main
对各个任务有更细粒度的控制,并且您正在使用static
"全局"变量。 您甚至可以添加一个task.shutdown()
方法来设置活动标志。
最后,正如@duffmo提到的,如果您总是只想运行一个线程,则应始终考虑使用其中一个线程池ExecutorService
。 像Executors.newFixedThreadPool(1)
. 但我不太清楚你是否一直只想要一个线程。 如果您使用ExecutorService
那么main
就可以了:
ExecutorService threadPool = Executors.newFixedThreadPool(1);
List<Future> futures = new ArrayList<Future>();
for (int i = 0; i <= 5; i++) {
// the monitor would not be needed
threadPool.submit(new Task(i + 65));
}
threadPool.shutdown();
for (Future future : futures) {
// this waits for the working task to finish
future.get();
}
但是,如果您需要像当前对monitor
所做的那样停止和启动后台任务,则此模型可能不起作用。
现在 naswer 是
0A, 0B, 0C, 0D,0E, 0F, 1A, 1B, 1C, 1D, 1E, 1F, 等待等待等待等待等待等待主中的最后一个命令
我在启动线程后添加了睡眠
import java.util.ArrayList;
public class Main extends Thread {
ArrayList<Thread> threads;
volatile static boolean ACTIVE = true;
public Main() {
super();
threads = new ArrayList<Thread>();
}
public void run(){
Object monitor = new Object();
for (int i = 0; i <= 5; i++) {
threads.add(new Thread(new Task(i + 65, monitor)));
}
long cT = System.currentTimeMillis();
for (int i = 0; i < threads.size(); i++) {
threads.get(i).start();
}
try{Thread.sleep(50);}catch(Exception e){e.printStackTrace();}
// System.out.println("BEFORE synchronized(monitor)");
synchronized(monitor){
while (System.currentTimeMillis() - cT < 1000) {
try{
monitor.notify();
Thread.sleep(500);
monitor.wait();}catch(Exception e){e.printStackTrace();}
}
// System.out.println("BEFORE ACTIVE= FALSE and after WHILE in Main");
ACTIVE = false;
for(int i = 0; i < threads.size(); i++){
System.out.println(threads.get(i).getState());
}
}
System.out.println("LAST COMMAND IN MAIN");
}
public static void main(String[] args) {
new Main().start();
//new Thread(new Task(65)).start();
}
}
和任务
public class Task implements Runnable {
int nr;
char character;
Object monitor;
public Task(int literaASCII, Object monitor) {
this.nr = 0;
this.monitor = monitor;
character = (char) (literaASCII);
}
@Override
public void run() {
synchronized (monitor) {
while (Main.ACTIVE) {
try {
// System.out.println("ENTERING WHILE IN TASK");
monitor.wait();
System.out.print(nr + "" + character + ", ");
nr++;
int r = (int) ((Math.random() * 50) + 50); // <500ms,1000ms)
Thread.sleep(r);
} catch (Exception e) {e.printStackTrace();}
monitor.notify();
// System.out.println("YYYYYYYYY");
}
System.out.println("AFTER WHILE IN Task");
}
System.out.println("I am saying goodbye " + character);
}
}