Я пишу часть javascript (ecmascript) в стороннем приложении, которое использует встроенный Rhino. Приложение может запускать несколько потоков Java для обработки данных одновременно. Кажется, что каждый поток Java начинает свой собственный встроенный контекст Rhino, который, в свою очередь, запускает мой скрипт.Несколько потоков Rhino (java) управляют одним и тем же файлом
Целью моего сценария является получение данных из приложения и использование его для хранения содержимого определенного файла. Мне нужно отказоустойчивое решение для обработки параллелизма из моего скрипта.
До сих пор, что я придумал, это обратиться к 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);
}
}
Q: Как я могу решить эту проблему в безопасной и надежной манере?
Я видел сообщения о Rhino sync()
, похожие на Java synchronized
, но это не работает между несколькими экземплярами Rhino.
UPDATE
Я попытался предложение использовать Synchronizer
с org.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 и во всех экземплярах Rhino, запущенных в одной виртуальной машине, что, как я предполагаю, является тем, о чем мы говорим (он использует синхронизацию Java, а также может координировать с встроенные средства параллелизма Java). –
Мое предположение, не будучи в состоянии проверить вашу установку (и без тестирования моей теории), заключается в том, что функцию нельзя вызвать с помощью класса java.lang.Object' как 'this'. Попробуйте 'return new Packages.org.mozilla.javascript.Synchronizer (fn, obj)', а затем вызовите возвращаемую функцию: 'synchronize (function() {writer.update()}, on)();' и посмотреть, будет ли это лучше. –
Я получаю сообщение об ошибке 'org.mozilla.javascript.EvaluatorException: Java-конструктор для« org.mozilla.javascript.Synchronizer »с аргументами function, java.lang.Class« не найден ». Глядя на источник, на самом деле нет конструктор для этого, я должен пройти (Scriptable, Object). – mvreijn