Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
停止非循环Java线程_Java_Sql_Multithreading_Thread Safety - Fatal编程技术网

停止非循环Java线程

停止非循环Java线程,java,sql,multithreading,thread-safety,Java,Sql,Multithreading,Thread Safety,这可能是因为我误解了我所读的内容,但所有在Java中杀死线程的示例似乎都表明,必须向线程发出杀死自己的信号;你不可能在没有严重风险的情况下从外部杀死它。问题是,所有关于如何“礼貌地”要求线程死亡的示例都有某种循环,因此您所要做的就是在每次迭代中观察一个标志 所以,我得到的是一个线程,它只需要一段时间(一系列SQL查询)就可以完成一些事情。我当然可以在每一步完成后进行检查,但它们并不是一个循环,我也不知道有一种非常优雅的方式来解决这个问题。下面是我正在做的一个例子: new Thread(new

这可能是因为我误解了我所读的内容,但所有在Java中杀死线程的示例似乎都表明,必须向线程发出杀死自己的信号;你不可能在没有严重风险的情况下从外部杀死它。问题是,所有关于如何“礼貌地”要求线程死亡的示例都有某种循环,因此您所要做的就是在每次迭代中观察一个标志

所以,我得到的是一个线程,它只需要一段时间(一系列SQL查询)就可以完成一些事情。我当然可以在每一步完成后进行检查,但它们并不是一个循环,我也不知道有一种非常优雅的方式来解决这个问题。下面是我正在做的一个例子:

new Thread(new Runnable(){
    public void run(){
        //query 1
        Connection conn = db.getConnection();
        Statement s = conn.createStatement();
        ResultSet rs = s.executeQuery("SELECT ...");
        while(rs.next()){
            //do stuff
        }

        //query 2
        rs = s.executeQuery("SELECT ...");
        while(rs.next()){
            //do stuff
        }

        //query 3
        rs = s.executeQuery("SELECT ...");
        while(rs.next()){
            //do stuff
        }
    }
}).start();
这是一个例子,我不使用匿名内部类,但它说明了我的run()方法无法优雅地停止自身。此外,即使我在每一步之后都进行检查,如果某个特定查询需要很长时间才能运行,那么在查询完成之前,该代码将无法停止

这段代码是为GUI应用程序编写的,我真的很想找到一种不使用thread.stop()快速杀死线程的好方法


EDIT-yshavit的回答帮了大忙,因为我不知道
语句.cancel()
存在。如果您好奇的话,我的特定问题的答案是构建一个更抽象的数据库访问类。该类在运行时必须创建一个子线程来执行查询和循环,并在每次迭代中检查当前线程(不是子线程)是否被中断。如果它确实被中断,它只调用Statement.cancel(),子线程将抛出异常并终止。并非所有JDBC驱动程序都支持
语句.cancel()
,但Oracle 11g支持。

找出需要一段时间的内容,然后取消它。如果花费时间最多的是
rs.next()
循环,则可以执行以下操作:

while(rs.next()){
    if (myVolatileBooleanSaysToStop) {
        return; // or whatever
    }
    //do stuff
}
如果需要一段时间的事情是语句,并且JDBC驱动程序/服务器支持
语句。取消
,那么您可以将
语句
发布到负责调用
语句的第二个线程。取消
(视情况而定)。我不确定,但我认为这将导致驱动程序产生
SQLException
,然后您可以以某种方式将其识别为来自取消,并相应地进行处理


也应该考虑重构。“运行一个查询,迭代其结果”有三个部分,可以分解成一个方法(然后该方法负责关闭语句等)。

一旦run()完成,Java线程将自动关闭。如果在循环中运行(),则中断循环,Thread.run将结束,线程将死亡。您也可以使用
return如果我没有弄错。

如果您不想从头开始实现自己的thread.kill()机制,您可以使用现有的API,在中管理线程创建,并使用来终止正在运行的线程:

ThreadPoolExecutor threadPoolExecutor = Executors.newSingleThreadExecutor();
Runnable longRunningTask = new Runnable();

// submit task to threadpool:
Future longRunningTaskFuture = threadPoolExecutor.submit(longRunningTask);

... ...
// At some point in the future, if you want to kill the task:
longRunningTaskFuture.cancel(true);
... ...

Cancel方法的行为将根据任务运行状态而有所不同,有关详细信息,请查看API

中断客户端的线程(即在线程外运行的代码):

要检查运行代码的线程是否已中断,请执行以下操作:

Thread.currentThread().isInterrupted()
另一种选择是尝试睡眠:

Thread.currentThread().sleep(1)
睡眠的好处在于,如果线程被中断(即InterruptedException),它将抛出一个异常,这就是为什么不忽略这些异常很重要的原因

您可以使用Thread.currentThread().isInterrupted()在while循环中添加检查,也可以检查语句之间是否存在休眠(1)。我不会在循环中睡觉,因为那会让你的代码慢下来。这是混合方法最好的地方:

if( Thread.currentThread().isInterrupted() ) throw new InterruptedException();
然后在run()方法的边界处捕捉到它并停止

关键是您必须定期检查外部客户机是否请求您关闭。如果一个线程中有6条语句。在这些语句之间进行检查将允许线程退出

public run() {
    try {
       doSomething();
       if( Thread.currentInstance().isInterrupted() ) throw new InterruptException();
       doNextSomething();
       if( Thread.currentInstance().isInterrupted() ) throw new InterruptException();
       doSomeMoreThings();
       if( Thread.currentInstance().isInterrupted() ) throw new InterruptException();
       doYetMoreThings();
    } catch( InterruptedException e ) {
       System.out.println("Duff man going down.");
    }
}

执行此操作与在循环中执行单个检查之间实际上没有区别。

如果不想中断线程,唯一的其他选择是以某种方式终止/取消长时间运行的查询。如果您可以异步启动查询,您可以等待结果准备就绪或收到终止信号,但是您需要设置一个volatile boolean并检查它,或者检查线程是否已被中断(并从另一个线程中断以使其关闭)。对于语句和结果集对象,许多数据库驱动程序都不是线程安全的,即使JDBC规范说它们应该是线程安全的。这就是我试图避免的,每次迭代时都添加该检查看起来太难看了。此外,它确实无法回避长期运行的查询问题。结果集只有在查询完成后才可用,不幸的是,我没有改进数据库结构以改进查询的选项。@monitorjbl关于丑陋之处,实际上没有其他选择。这就是我建议重构代码的原因——它会整合丑陋之处。至于查询本身需要很长时间,如果因为驱动程序的原因而无法取消查询,那么您的应用程序就没有太多可以做的事情了。@yshavit我的实际代码有单独的方法来处理这些问题,但它不能很容易地合并。我可能得自己做一把刀;我不打算那样构建基础设施,因为这段代码不会被重用很多,但我想这是整合一切的好借口。谢谢你的建议@gordy您必须启动一个子线程来使用语句执行查询。然后,它的父对象在子对象还活着的时候循环,监视Thread.isInterrupted()是否为true。若遇到这种情况,它所要做的就是运行语句。cancel()。我可以验证这确实适用于Orac
public run() {
    try {
       doSomething();
       if( Thread.currentInstance().isInterrupted() ) throw new InterruptException();
       doNextSomething();
       if( Thread.currentInstance().isInterrupted() ) throw new InterruptException();
       doSomeMoreThings();
       if( Thread.currentInstance().isInterrupted() ) throw new InterruptException();
       doYetMoreThings();
    } catch( InterruptedException e ) {
       System.out.println("Duff man going down.");
    }
}