Java关闭挂钩

Java关闭挂钩,java,multithreading,Java,Multithreading,在IDE中使用IntelliJ IDE、java 1.8、lang level 6(以及命令提示符下的默认值) 使用以下命令行(Windows 7)编译和运行: 给出下面的代码,我想做的是关闭应用程序中所有正在运行的线程(如果操作系统或JVM为我这么做的话,也许我不需要这么做)。我有一个线程MyThread,它依次保存它正在管理的线程列表(当被main中断时,它会向列表中的每个线程发送一个中断) 当我运行代码时,我会得到输出保持忙碌。每隔2秒打印一次。当我按下CTRL-C时,关闭钩子运行(我将p

在IDE中使用IntelliJ IDE、java 1.8、lang level 6(以及命令提示符下的默认值)

使用以下命令行(Windows 7)编译和运行:

给出下面的代码,我想做的是关闭应用程序中所有正在运行的线程(如果操作系统或JVM为我这么做的话,也许我不需要这么做)。我有一个线程MyThread,它依次保存它正在管理的线程列表(当被main中断时,它会向列表中的每个线程发送一个中断)

当我运行代码时,我会得到输出
保持忙碌。
每隔2秒打印一次。当我按下CTRL-C时,关闭钩子运行(我将println消息放入其中以确认),但这就是我看到的所有输出。我从未看到取消的
nr主()的结尾。。。因此,我还必须假设Cancel方法也没有运行

那么,首先,我需要关心这个吗?我可以(主要)在isInterrupted上循环并让程序停止吗?如何取消所有子线程

import java.util.HashMap;

class MyThread extends Thread {}

public class Main
{
    private static volatile boolean running = true;
    // List of active threads.
    private HashMap<String, Thread> threads = new HashMap<String, Thread>();

    public static void main(String[] args) throws InterruptedException
    {
        // Get an instance of the Main class.
        Main myApp = new Main();

        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            public void run()
            {
                running = false;
            }
        });

        // Loop until system shutdown.
        while (running && !Thread.currentThread().isInterrupted())
        {
            myApp.CreateMyThread();

            // In real code, I have a wait() here, rather than the following lines.

            System.out.println("Keeping busy.");
            Thread.sleep(2000);
        }

        System.out.println("Cancelled.");

        // Kill all threads.
        myApp.Cancel();

        System.exit(0);
    }

    private void Cancel()
    {
        for (Thread t : threads.values())
        {
            t.interrupt();
        }
    }

    private void CreateMyThread()
    {
        if (threads.get("mythread") instanceof MyThread)
        {
            // Already exists.
            return;
        }

        MyThread t = new MyThread();
        t.start();
        threads.put("mythread", t);
    }
}
import java.util.HashMap;
MyThread类扩展线程{}
公共班机
{
private static volatile boolean running=true;
//活动线程的列表。
私有HashMap线程=新HashMap();
公共静态void main(字符串[]args)引发InterruptedException
{
//获取主类的实例。
Main myApp=new Main();
Runtime.getRuntime().addShutdownHook(新线程()
{
公开募捐
{
运行=错误;
}
});
//循环直到系统关闭。
运行时(运行&!Thread.currentThread().isInterrupted())
{
myApp.CreateMyThread();
//在实际代码中,这里有一个wait(),而不是下面几行。
System.out.println(“保持忙碌”);
《睡眠》(2000年);
}
System.out.println(“取消”);
//杀死所有线程。
myApp.Cancel();
系统出口(0);
}
私人作废取消()
{
对于(线程t:threads.values())
{
t、 中断();
}
}
私有void CreateMyThread()
{
if(threads.get(“mythread”)实例mythread)
{
//已经存在。
返回;
}
MyThread t=新的MyThread();
t、 start();
线程。放置(“mythread”,t);
}
}
编辑

所以,我改变了我的代码如下。创建了一个包含hashmap的Threadlist类,其方法使用关键字“synchronized”添加/删除线程并取消所有线程。main包含此类的静态实例。然后,我的关闭处理程序调用CancelThreads方法关闭所有正在运行的线程。问:这真的是线程安全的吗,即:在方法上进行同步是否真的会阻止一个方法在另一个方法进行时运行

import java.util.HashMap;

class MyThread extends Thread {}

class Threadlist
{
    // List of threads.
    private HashMap<String, Thread> threads = new HashMap<String, Thread>();

    public synchronized void AddThread(String name, Thread thread)
    {
        threads.put(name, thread);
    }

    public synchronized Thread GetThread(String name)
    {
        return threads.get(name);
    }

    public synchronized void CancelThreads()
    {
        for (Thread t : threads.values())
        {
            System.out.printf("Killing a thread by the name of '%s'\n", t.getName());
            t.interrupt();
        }
    }
}

public class Main
{
    private static volatile boolean running = true;
    // List of active threads.
    private static Threadlist threads = new Threadlist();

    public static void main(String[] args) throws InterruptedException
    {
        // Get an instance of the Main class.
        Main myApp = new Main();

        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            public void run()
            {
                threads.CancelThreads();
                running = false;
            }
        });

        // Loop until system shutdown.
        while (running && !Thread.currentThread().isInterrupted())
        {
            myApp.CreateMyThread();

            // In real code, I have a wait() here, rather than the following lines.

            System.out.println("Keeping busy.");
            Thread.sleep(2000);
        }

        System.out.println("Cancelled.");

        System.exit(0);
    }

    private void CreateMyThread()
    {
        if (threads.GetThread("mythread") instanceof MyThread)
        {
            // Already exists.
            return;
        }

        MyThread t = new MyThread();
        t.start();
        threads.AddThread("mythread", t);

}
import java.util.HashMap;
MyThread类扩展线程{}
类线程列表
{
//线程列表。
私有HashMap线程=新HashMap();
公共同步的void AddThread(字符串名称,线程)
{
线程。put(名称、线程);
}
公共同步线程GetThread(字符串名称)
{
返回threads.get(name);
}
公共同步的void CancelThreads()
{
对于(线程t:threads.values())
{
System.out.printf(“以'%s'\n',t.getName()的名称终止线程”);
t、 中断();
}
}
}
公共班机
{
private static volatile boolean running=true;
//活动线程的列表。
private static Threadlist threads=new Threadlist();
公共静态void main(字符串[]args)引发InterruptedException
{
//获取主类的实例。
Main myApp=new Main();
Runtime.getRuntime().addShutdownHook(新线程()
{
公开募捐
{
线程。取消线程();
运行=错误;
}
});
//循环直到系统关闭。
运行时(运行&!Thread.currentThread().isInterrupted())
{
myApp.CreateMyThread();
//在实际代码中,这里有一个wait(),而不是下面几行。
System.out.println(“保持忙碌”);
《睡眠》(2000年);
}
System.out.println(“取消”);
系统出口(0);
}
私有void CreateMyThread()
{
if(threads.GetThread(“mythread”)实例mythread)
{
//已经存在。
返回;
}
MyThread t=新的MyThread();
t、 start();
线程。添加线程(“mythread”,t);
}
}


我还开始创建一个ShutdownHook类,扩展Thread,它会通过构造函数接受main的threads对象,然后在run()方法中取消线程,但我看不到如何同时更改main->running值,因此,上面是我的方法。

您的关闭挂钩是一个单独的线程,在关闭发生时启动(希望没有保证)。与此同时,您的主线程仍在进行中,但它即将被杀死。这可能会起作用,但在中断杀死主线程之前,中断可能不会给代码中的2秒钟时间


相反,您应该与您的关闭钩子共享生成线程的列表,并让该钩子尝试直接中断/关闭生成线程。

一旦关闭钩子完成运行VM停止(实际上中间还有另一个步骤,但与本讨论无关)

这里的关键是你的关闭钩子需要足够长的时间才能让其他线程清理,你可以通过在另一个线程上调用关闭钩子来完成这一点,并且有一个超时。这将允许关闭挂钩在另一个线程之后或超过指定的超时时结束
import java.util.HashMap;

class MyThread extends Thread {}

class Threadlist
{
    // List of threads.
    private HashMap<String, Thread> threads = new HashMap<String, Thread>();

    public synchronized void AddThread(String name, Thread thread)
    {
        threads.put(name, thread);
    }

    public synchronized Thread GetThread(String name)
    {
        return threads.get(name);
    }

    public synchronized void CancelThreads()
    {
        for (Thread t : threads.values())
        {
            System.out.printf("Killing a thread by the name of '%s'\n", t.getName());
            t.interrupt();
        }
    }
}

public class Main
{
    private static volatile boolean running = true;
    // List of active threads.
    private static Threadlist threads = new Threadlist();

    public static void main(String[] args) throws InterruptedException
    {
        // Get an instance of the Main class.
        Main myApp = new Main();

        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            public void run()
            {
                threads.CancelThreads();
                running = false;
            }
        });

        // Loop until system shutdown.
        while (running && !Thread.currentThread().isInterrupted())
        {
            myApp.CreateMyThread();

            // In real code, I have a wait() here, rather than the following lines.

            System.out.println("Keeping busy.");
            Thread.sleep(2000);
        }

        System.out.println("Cancelled.");

        System.exit(0);
    }

    private void CreateMyThread()
    {
        if (threads.GetThread("mythread") instanceof MyThread)
        {
            // Already exists.
            return;
        }

        MyThread t = new MyThread();
        t.start();
        threads.AddThread("mythread", t);

}
    final Object lock = new Object(); //Lock object for synchronization.
    final Thread mainThread = Thread.currentThread(); //Reference to the current thread.

    Runtime.getRuntime().addShutdownHook(new Thread()
    {
        public void run()
        {
            try{
                synchronized(lock){
                  running = false;
                  lock.notifyAll();
                }

                mainThread.join(4000);
            }catch(InterruptedException){
               //Interrupted.
            }
        }
    });

    synchronized(lock){
        while (running && !Thread.currentThread().isInterrupted())
        {
            myApp.CreateMyThread();

            System.out.println("Keeping busy.");
            lock.wait(2000); 
        }
     }