Java, пишущий сценарий API - как остановить оценку

Преимущество:

  • Только одно место для обновления блоков
  • Вы используете немного меньше пространства на жестком диске

Недостаток:

  • , Если необходимо обновить только один веб-сайт, Вы не можете. Можно закончить другими веб-сайтами в веб-сервере, поврежденном

Рекомендация: Оставьте GAC MS и друзьям. Гигабайт является очень дешевым теперь.

6
задан special0ne 21 October 2009 в 14:35
поделиться

3 ответа

Here's some code showing the Future implementation and the Thread.stop() one. This is an interesting problem, and it points out the need for a hook in a ScriptEngine to be able to halt whatever script it's running for whatever reason. I wonder whether this would break the assumptions in most implementations since they assume eval() will be executed in a single-threaded (blocking) environment?

Anyway, the results of executing the code below:

// exec with Thread.stop()
$ java ExecJavascript 
Java: Starting thread...
JS: Before infinite loop...
Java: ...thread started
Java: Thread alive after timeout, stopping...
Java: ...thread stopped
(program exits)

// exec with Future.cancel()
$ java ExecJavascript 1
Java: Submitting script eval to thread pool...
Java: ...submitted.
JS: Before infinite loop...
Java: Timeout! trying to future.cancel()...
Java: ...future.cancel() executed
(program hangs)

Here's the full program:

import java.util.concurrent.*;
import javax.script.*;

public class ExecJavascript
{
private static final int TIMEOUT_SEC = 5;
public static void main( final String ... args ) throws Exception 
{
    final ScriptEngine engine = new ScriptEngineManager()
        .getEngineByName("JavaScript");
    final String script = 
        "var out = java.lang.System.out;\n" +
        "out.println( 'JS: Before infinite loop...' );\n" +
        "while( true ) {}\n" +
        "out.println( 'JS: After infinite loop...' );\n";
    if ( args.length == 0 ) {
        execWithThread( engine, script );
    }
    else {
        execWithFuture( engine, script );
    }
}

private static void execWithThread( 
    final ScriptEngine engine, final String script )
{
    final Runnable r = new Runnable() {
        public void run() {
            try {
                engine.eval( script );
            }
            catch ( ScriptException e ) {
                System.out.println( 
                    "Java: Caught exception from eval(): " + e.getMessage() );
            }
        }
    };
    System.out.println( "Java: Starting thread..." );
    final Thread t = new Thread( r );
    t.start();
    System.out.println( "Java: ...thread started" );
    try {
        Thread.currentThread().sleep( TIMEOUT_SEC * 1000 );
        if ( t.isAlive() ) {
            System.out.println( "Java: Thread alive after timeout, stopping..." );
            t.stop();
            System.out.println( "Java: ...thread stopped" );
        }
        else {
            System.out.println( "Java: Thread not alive after timeout." );
        }
    }
    catch ( InterruptedException e ) {
        System.out.println( "Interrupted while waiting for timeout to elapse." );
    }
}

private static void execWithFuture( final ScriptEngine engine, final String script )
    throws Exception
{
    final Callable<Object> c = new Callable<Object>() {
        public Object call() throws Exception {
            return engine.eval( script );
        }
    };
    System.out.println( "Java: Submitting script eval to thread pool..." );
    final Future<Object> f = Executors.newCachedThreadPool().submit( c );
    System.out.println( "Java: ...submitted." );
    try {
        final Object result = f.get( TIMEOUT_SEC, TimeUnit.SECONDS );
    }
    catch ( InterruptedException e ) {
        System.out.println( "Java: Interrupted while waiting for script..." );
    }
    catch ( ExecutionException e ) {
        System.out.println( "Java: Script threw exception: " + e.getMessage() );
    }
    catch ( TimeoutException e ) {
        System.out.println( "Java: Timeout! trying to future.cancel()..." );
        f.cancel( true );
        System.out.println( "Java: ...future.cancel() executed" );
    }
} 
}
3
ответ дан 17 December 2019 в 00:11
поделиться

Запустить оценку в отдельном потоке и прервать ее через 15 секунд с помощью Thread.interrupt (). Это остановит eval и выдаст InterruptedException, которое вы можете поймать и вернуть статус сбоя.

Лучшим решением было бы иметь какой-то асинхронный интерфейс для механизма сценариев, но, насколько я мог видеть, этого не происходит. существует.

РЕДАКТИРОВАТЬ:

Как указал sfussenegger, прерывание не работает с механизмом сценария, поскольку он никогда не спит и не входит в какое-либо состояние ожидания для прерывания. Я не мог найти периодического обратного вызова в объектах ScriptContext или Bindings, которые можно было бы использовать в качестве ловушки для проверки прерываний. Однако есть один метод, который действительно работает: Thread.stop (). Он устарел и небезопасен по ряду причин. но для полноты картины я опубликую здесь свой тестовый код вместе с реализацией Криса Винтерса для сравнения. У версии Криса истечет тайм-аут, но фоновый поток останется запущенным, прерывание () ничего не делает, а stop () убивает поток и возобновляет управление основному потоку:

import javax.script.*;
import java.util.concurrent.*;

class ScriptRunner implements Runnable {

    private String script;
    public ScriptRunner(String script) {
            this.script = script;
    }

    public ScriptRunner() {
            this("while(true);");
    }

    public void run() {
            try {
            // create a script engine manager
            ScriptEngineManager factory = new ScriptEngineManager();
            // create a JavaScript engine
            ScriptEngine engine = factory.getEngineByName("JavaScript");
            // evaluate JavaScript code from String
            System.out.println("running script :'" + script + "'");
            engine.eval(script);
            System.out.println("stopped running script");
            } catch(ScriptException se) {
                    System.out.println("caught exception");
                    throw new RuntimeException(se);
            }
            System.out.println("exiting run");
    }
}

public class Inter {

    public void run() {
            try {
             Executors.newCachedThreadPool().submit(new ScriptRunner()).get(15, TimeUnit.SECONDS);
            } catch(Exception e) {
                    throw new RuntimeException(e);
            }
    }

    public void run2() {
            try {
            Thread t = new Thread(new ScriptRunner());
            t.start();
            Thread.sleep(1000);
            System.out.println("interrupting");
            t.interrupt();
            Thread.sleep(5000);
            System.out.println("stopping");
            t.stop();
            } catch(InterruptedException ie) {
                    throw new RuntimeException(ie);
            }
    }

    public static void main(String[] args) {
            new Inter().run();
    }
}
3
ответ дан 17 December 2019 в 00:11
поделиться

Если вы не желаете использовать Thread.stop () (а вам это действительно следует), кажется, чтобы не было возможности выполнить ваше требование с помощью javax.script API.

Если вы используете движок Rhino напрямую и фактическая производительность не слишком важна, вы можете реализовать ловушку в Context.observeInstructionCount, чтобы прервать или преждевременно завершить выполнение скрипта. Ловушка вызывается для каждой выполненной инструкции JavaScript после достижения порога (количества инструкций), установленного с помощью setInstructionObserverThreshold. Вам необходимо самостоятельно измерить время выполнения, поскольку вам предоставляется только количество выполненных инструкций, и это может иметь существенное влияние на производительность. Я не уверен,

2
ответ дан 17 December 2019 в 00:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: