【问题标题】:Multiple Rhino (java) threads manipulate the same file多个 Rhino (java) 线程操作同一个文件
【发布时间】:2015-06-24 13:17:49
【问题描述】:

我正在使用嵌入式 Rhino 的第 3 方应用程序中编写一段 javascript (ecmascript)。应用程序可能会启动多个 Java 线程来同时处理数据。似乎每个 Java 线程都启动了自己的嵌入式 Rhino 上下文,然后运行我的脚本。

我的脚本的目的是从应用程序接收数据并使用它来维护特定文件的内容。我需要一个故障安全解决方案来处理脚本中的并发。

到目前为止,我想出的是调用java并使用java.nio.channels.FileLock。但是,文档here 指出:

代表整个 Java 虚拟机持有文件锁。它们不适用于控制同一虚拟机内的多个线程对文件的访问。

果然,阻塞调用FileChannel.lock()没有阻塞反而抛出异常,导致如下丑陋的代码:

var count = 0;
while ( count < 100 )
{
    try 
    {
        var rFile = new java.io.RandomAccessFile(this.mapFile, "rw");
        var lock = rFile.getChannel().lock();
        try
        {
            // Here I do whatever the script needs to do with the file
        }
        finally
        {
            lock.release();
        }
        rFile.close();
        break;
    } catch (ex) {
        // This is reached whenever another instance has a lock
        count++;
        java.lang.Thread.sleep( 10 );
    }       
}

问:如何安全可靠地解决这个问题?

我看到过有关 Rhino sync() 与 Java synchronized 相似的帖子,但这似乎在 Rhino 的多个实例之间不起作用。

更新

我尝试过使用Synchronizerorg.mozilla.javascript.tools.shell.Global 作为模板的建议:

function synchronize( fn, obj )
{
    return new Packages.org.mozilla.javascript.Synchronizer(fn).call(obj);
}

接下来,我使用这个函数如下:

    var mapFile = new java.io.File(mapFilePath);
    // MapWriter is a js object
    var writer = new MapWriter( mapFile, tempMap );
    var on = Packages.java.lang.Class.forName("java.lang.Object");
    // Call the writer's update function synchronized
    synchronize( function() { writer.update() } , on );

但是我看到两个线程同时进入update() 函数。我的代码有什么问题?

【问题讨论】:

  • sync() 在单个 Rhino 实例中的所有上下文之间以及在单个 VM 中运行的所有 Rhino 实例之间工作,我假设这就是我们正在谈论的(它使用 Java 同步,所以也可以与原生 Java 并发工具配合使用)。
  • 我的猜测是,在无法测试您的设置(也无法亲自测试我的理论)的情况下,无法使用 Class java.lang.Object 作为 this 调用函数。尝试return new Packages.org.mozilla.javascript.Synchronizer(fn,obj),然后调用返回的函数:synchronize(function() { writer.update() }, on)();,看看是否更好。
  • 我得到一个错误org.mozilla.javascript.EvaluatorException: Java constructor for "org.mozilla.javascript.Synchronizer" with arguments "function,java.lang.Class" not found. 查看源代码,确实没有构造函数,我必须传入(Scriptable,Object)。
  • 是的,但一切都是对象。 Rhino 翻译这个论点的方式肯定有一些问题。或者你使用的是早期版本的 Rhino,也许? Packages.org.mozilla.javascript.Context.getCurrentContext().getImplementationVersion() 带给你什么?
  • 也许你是对的:Rhino Version: Rhino 1.6 release 7 2007 08 19 这似乎有点老了。不幸的是,我无法控制(此版本的)应用程序。不过,我会告诉开发团队在下一个版本中开始使用 [rd]ecent 版本。

标签: javascript java multithreading synchronization rhino


【解决方案1】:

根据 Rhino 的嵌入方式,有两种可能:

    1234563缺席。 (早期版本只有一个参数方法,因此除非您的第三方应用程序使用最新版本,否则您可能需要使用该版本或推出自己的版本;见下文。)
  1. 如果应用程序不使用 Rhino shell,而是使用不包含并发工具的自定义嵌入,您需要推出自己的版本。 sync 的源代码是一个很好的起点(参见 GlobalSynchronizer 的源代码;您应该能够像 Global 使用它一样开箱即用地使用 Synchronizer)。

问题可能是您尝试同步的对象不是跨上下文共享的,而是由嵌入或其他东西多次创建的。如果是这样,您可能需要使用某种 hack,尤其是在您无法控制嵌入的情况下。如果您无法控制嵌入,则可以使用某种 VM 全局对象进行同步,例如 Runtime.getRuntime() 或其他东西(我想不出我立即知道的任何单个对象,但我怀疑有几个那些使用像 Runtime 这样的单例 API 的人。)

另一个需要同步的对象是 Packages.java.lang.Class.forName("java.lang.Object"),它应该在所有上下文中引用同一个对象(Object 类),除非嵌入的类加载器设置非常不寻常。

【讨论】:

  • 我确定sync() 不可用(ergo 自定义嵌入)。我第一次尝试Synchronizer 没有成功,这就是为什么我认为它仅适用于单个 Rhino 实例。我会看Global源代码,再试一次。
  • 你会看看我更新的帖子吗?我显然在某个地方犯了错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-05
  • 2011-04-01
相关资源
最近更新 更多