java - JVM 在创建线程并在其中执行网络操作时突然关闭

标签 java multithreading threadpool jvm-hotspot jvm-crash

This is an issue with I am trying to fix, maybe a bug in JRE please vote to reopen this question. It's very selfish approach to mark something off topic if you are not competent enough to understand some problem.

Java版本

java版本“1.7.0_45” Java(TM) SE 运行时环境(版本 1.7.0_45-b18) Java HotSpot(TM) 64 位服务器 VM(内部版本 24.45-b08,混合模式)

遵循两个版本的代码都会产生相同的崩溃。

客户端计算机使用在 Windows Server 2003 64 位上运行的 Server Maching(使用 Oracle 10g 数据库和 Hibernate 3.0)调用部署在 Tomcat 7 中的 Servlet。

当我尝试将负载放在 Servlet 上进行负载测试时,我编写了以下两种方法,它们仅创建一个线程并调用同步方法,但没有任何日志“Eclipse 中的进程终止”的堆栈跟踪。

我不知道崩溃的原因,如果我创建 500 个线程,那么它会在 487 处崩溃,如果我创建 1000 个线程,那么它会在 874 处崩溃。我不知道真正的原因是什么。我配置了StuckThreadDetectionValve检测长时间运行的线程。

https://stackoverflow.com/a/7484800/185022

我将在这里分享所有更新。如果您知道可能出了什么问题,请至少给我一个提示。

** 两个代码都会产生相同的崩溃 **

Code 1:

public class TokenTest {
    static int count = 0;

    public static void main(String[] args) {
        try {
            System.out.println("Start " + new Date());
            final ApplicationServiceClient app = WSClient.getClient("http://192.168.1.15:81/az-server", ApplicationServiceClient.class);
            final int max = 50;
            ExecutorService executor = Executors.newFixedThreadPool(max);

            for (int i = 1; i <= max; i++) {

                executor.execute(new Runnable() {
                    public void run() {
                        try {
                            System.out.print(++count +",");
                            app.verifyToken("7056451004350030976"); //Network Synchronous Operation, calls a Servlet that is deployed in another Server Machine, Using Tomcat 7.0
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }

                    }
                });
            }
            executor.shutdown();

            while (!executor.isShutdown()) {
                System.out.println("END " + new Date());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }   

}

Code 2:

public class TokenTest {
    static int count = 0;

    public static void main(String[] args) {
        try {
            System.out.println(new Date());
            final ApplicationServiceClient app = WSClient.getClient("http://192.168.1.15:81/az-server", ApplicationServiceClient.class);
            final int max=250;
            for (int i = 1; i <= max; i++) {
                Thread t = new Thread() {
                    public void run() {
                        app.verifyToken("7056451004350030976");//Network Synchronous Operation
                        System.out.print(count++);
                        System.out.print(", ");
                        if (count >= max)
                            System.out.println("\n" + new Date());
                    }
                };

                t.start();
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }



}

注意: 该服务器托管在另一台 Windows Server 2003 64 位计算机上。

已更新 它只是终止我在 Eclipse 中的 Java 进程,如果我给出像 5000 这样的值,那么它会停留在 2800 上,什么也不会发生,也不会终止我的进程。这是控制台快照。

Console

更新* 感谢 S.Yavari。他引领了正确的方向。配置后Stuck_Thread_Detection_Valve在 Tomcat 上并中断卡住线程的线程,我能够毫无问题地在服务器上生成 500K 客户端的负载,并且在开始新请求之前还提供 100 毫秒的 sleep 。

下面是代码:

public class StageOne {

    final ApplicationServiceClient appClient = WSClient.getClient(Main.url, ApplicationServiceClient.class);
    final SecureWebServiceClient secureClient = WSClient.getClient(Main.url, SecureWebServiceClient.class);
    final static List<Long> times = new Vector<Long>();
    String token = "";

    public String authenticateClient() {

        token = appClient.authenticateClient("az_y", "az", "0");
        // System.out.println("Registration Response: " + token);
        return token;
    }

    private void getDefaultDepartmentName() {

        String deptname = appClient.getDefaultDepartmentName();
        // System.out.println("Department: " + deptname);
    }

    private void getLocation() {

        List<String> location = appClient.listLocation();
        // System.out.println("Location: " + location);
    }

    private void registerClient_() {
        secureClient.setToken(token);
        String respon = secureClient.registerClient("Buddy AZ", "443", "njuy", "1");

        // System.out.println(respon);

    }

    static int count = 0;

    public static void main(String[] args) {

        int pool = 500000;

        final ExecutorService execotors = Executors.newFixedThreadPool(pool);

        for (int i = 0; i < pool; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            execotors.execute(new Runnable() {

                @Override
                public void run() {

                    long startTime = System.nanoTime();

                    StageOne one = new StageOne();

                    one.authenticateClient();
                    one.getDefaultDepartmentName();
                    one.getLocation();
                    one.registerClient_();

                    long EndTime = System.nanoTime();

                    // System.out.println("Time in Seconds ("+ (++count) +")" + TimeUnit.NANOSECONDS.toSeconds(EndTime - startTime));
                    times.add(TimeUnit.NANOSECONDS.toSeconds(EndTime - startTime));
                }
            });
        }
        execotors.shutdown();

        while (!execotors.isShutdown()) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                // TODO: handle exception
            }
        }

        Collections.sort(times);
        long sum = 0;
        for (int i = 0; i < times.size(); i++) {
            sum += times.get(i);
        }
        long result = sum / Math.max(1, times.size());


        System.out.println("Min Response Time: " + times.get(0));
        System.out.println("Average Response Time: " + result);
        System.out.println("Max Response Time: " + times.get(times.size() - 1));

    }

}

最佳答案

我认为这只是一个线程问题。使用此代码:

public class Test2 {
    public static final Object LOCK = new Object();
    static int count = 0;

    public static void main(String[] args) {
        try {
            System.out.println(new Date());
            final ApplicationServiceClient app = WSClient.getClient("http://192.168.1.15:81/az-server", ApplicationServiceClient.class);
            final int max=250;
            for (int i = 1; i <= max; i++) {
                Thread t = new Thread() {
                    public void run() {
                        synchronized (LOCK) {
                            app.verifyToken("7056451004350030976");
                        }
                        System.out.print(count++);
                        System.out.print(", ");
                        if (count >= max)
                            System.out.println("\n" + new Date());
                    }
                };

                t.start();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

这个方法(verifyToken)必须是线程安全的,否则在线程内使用这个方法会遇到很多问题。

关于java - JVM 在创建线程并在其中执行网络操作时突然关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20728451/

相关文章:

java - 如何使用线程在不同系统中运行同一个java项目

Ruby 1.9 线程池

java - Ada 中的构造函数

java多线程cpu利用率

java - ExecutorService 对单个线程的时间限制

c++ - 如何绘制 UML 来说明在临界区工作的 2 个线程

java - 对我的客户端 Java 程序进行多线程处理

java - 在类 block 内声明和实例化

java - 我的 Java 代码无法运行,为什么? (只有几行)

java - 如何使用 Spring JMS 支持在运行时创建 JMS 队列?