在java中正确结束线程

在java中正确结束线程,java,multithreading,Java,Multithreading,我对Java中的线程有一个问题。 我想写一个程序,其中有一个类Main,它有一些类(类任务)的线程数组列表,它只写一个字母和数字。Object Main只是从ArrayList中唤醒一个线程,让它在同一个对象(Main)睡眠另一个线程时执行某些操作。 但是,即使我将Main.ACTIVE更改为false,也会出现一个问题。它不会结束所有线程,有些线程会继续运行,这是随机的,我只想让它们结束并写入: 我是说goodbay+字符-诸如此类的东西 public class Main extends T

我对Java中的线程有一个问题。 我想写一个程序,其中有一个类Main,它有一些类(类任务)的线程数组列表,它只写一个字母和数字。Object Main只是从ArrayList中唤醒一个线程,让它在同一个对象(Main)睡眠另一个线程时执行某些操作。 但是,即使我将Main.ACTIVE更改为false,也会出现一个问题。它不会结束所有线程,有些线程会继续运行,这是随机的,我只想让它们结束并写入:

我是说goodbay+字符-诸如此类的东西

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类主线程扩展{
阵列列表线程;
静态布尔活动=真;
公用干管(){
超级();
threads=newarraylist();
}
公开募捐{
对象监视器=新对象();

对于(int i=0;i您的问题是,对于初学者来说,
ACTIVE
应该标记为
volatile
。任何由多个线程共享的变量都需要以某种方式进行
同步
或标记为
volatile
,以便它的读写周围有一个内存屏障

从布尔的角度来看,您可以做的另一件事是使用
AtomicBoolean
类,而不是
volatile boolean

<> >代替“<代码>静态易失性布尔值< /代码>”,您可以考虑对每个<代码>任务对象具有<代码>易失性布尔< /代码>,以便<>代码>主< /COD>对单个任务有更细粒度的控制,并且您使用的是<代码>静态< /代码>“全局”变量。您甚至可以添加<代码>任务。
设置活动标志的方法

P>最后,正如@ DuffMo所提到的,如果你总是只想有一个线程运行,你就应该总是考虑使用一个线程池<代码> ExcutoService < /C>。。但我不能确定您是否始终只需要一个线程。如果您使用
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();
}
ExecutorService线程池=Executors.newFixedThreadPool(1);
列表期货=新的ArrayList();

对于(inti=0;i我建议您查看
java.util.concurrent
包中更现代的并发类,尤其是
ExecutorService
。然后阅读“java并发在实践中”。

现在是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();

}

}
import java.util.ArrayList;
公共类主线程扩展{
阵列列表线程;
volatile static boolean ACTIVE=true;
公用干管(){
超级();
threads=newarraylist();
}
公开募捐{
对象监视器=新对象();

对于(int i=0;i为什么要手动实现线程池?
Executors
类中实现了一系列预定义的线程池。如果适用,应该添加作业标记(似乎是这样的)。不是我的作业。这是我的朋友,我想教他简单的线程管理。我喜欢其他工具。我不能使用执行器队列、锁和类似工具。这是禁止的。我将活动更改为易失性,但效果保持不变0A、0B、0C、0D、0E、1A、1B、1C、1D、1E、2A、2B、2C、2D、2E、等待块ED MAIN中的最后一个命令在执行任务时我说再见了,我有点惊讶@Robert它居然会运行。就因为你调用了
start()
并不意味着线程将立即运行,因此有可能
main
将是第一个在监视器上同步的线程。第一个
notify
main不会做任何事情,因为没有人在等待。它将
睡眠
,然后
等待
等待。然后所有分叉线程将运行到
wait
调用,程序将挂起。没有人可以调用
notify
。我想这取决于有多少线程快速启动并将
main
放入
wait()
。在启动线程后,尝试在
main
中睡眠。现在答案总是0A、0B、0C、0D、0E、0F、1A、1B、1C、1D、1E、1F,等待main中的最后一个命令。我正在页面下方的答案中添加代码
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);
}