私はSQLiteデータベースにアクセスするアプリケーションを開発中です。問題は、DBにクエリがあるときにロックされることです。ほとんどの場合、アプリの流れは非常に線形であるため、これは問題ではありません。Javaでデータベースにアクセスするスレッドを管理する
しかし、私は非常に長い計算プロセスをユーザーがトリガーしています。このプロセスでは、計算の間にデータベースへの複数の呼び出しが行われます。
私はJavafxのprogressIndicatorとJavafx.Concurrencyフレームワークからのサービスを使用していたので、ユーザーに視覚的なフィードバックを求めていました。 これは、ユーザーがアプリケーションを自由に移動できるようにし、潜在的にデータベースへの他の呼び出しを引き起こすことになります。
これは、データベースファイルがロックされているという例外を引き起こしました。 このケースが発生したときにそのスレッドが実行されないようにする方法がありますが、私は明確な例をオンラインで見つけることができませんでした。それらのほとんどは単純化されており、スケーラビリティのある方法が欲しいです。私はキャンセル()メソッドを使用してみましたが、これはスレッドが時間内にキャンセルされることを保証するものではありません。
isCancelledのコードのすべての部分をチェックインできないため、スレッドがキャンセルされてから効果的に停止するまでに時間がかかることがあります。
私は以下の解決策を考えましたが、効率性と競争状態の回避と吊り下げの面でより良い方法があるかどうかを知りたいと思います。
// Start service
final CalculatorService calculatorService = new CalculatorService();
// Register service with thread manager
threadManager.registerService(CalculatorService);
// Show the progress indicator only when the service is running
progressIndicator.visibleProperty().bind(calculatorService.runningProperty());
calculatorService.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent workerStateEvent) {
System.out.println("SUCCEEDED");
calculatorService.setStopped(true);
}
});
// If something goes wrong display message
calculatorService.setOnFailed(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent workerStateEvent) {
System.out.println("FAILED");
calculatorService.setStopped(true);
}
});
// Restart the service
calculatorService.restart();
これは、サービスは、このインタフェースを実装
public class CalculatorService extends Service implements CustomService {
private AtomicBoolean stopped;
private CalculatorService serviceInstance;
public FindBundleService() {
stopped = new AtomicBoolean(false);
instance = this;
}
@Override
protected Task<Results> createTask() {
return new Task<Result>() {
@Override
protected Result call() throws Exception {
try {
Result = calculationMethod(this, serviceInstance);
return Result;
} catch (Exception ex) {
// If the thread is interrupted return
setStopped(true);
return null;
}
}
};
}
@Override
public boolean isStopped() {
return stopped.get();
}
@Override
public void setStopped(boolean stopped) {
this.stopped.set(stopped);
}
}
(停止または停止していない)私は、サービスの状態を設定するために使用できるメソッドが含まれるようにサブクラス化してきた私のサービスクラスであるI
public interface CustomService {
/**
* Method to check if a service has been stopped
*
* @return
*/
public boolean isStopped();
/**
* Method to set a service as stopped
*
* @param stopped
*/
public void setStopped(boolean stopped);
}
すべてのサービスは、シングルトンクラスであるスレッドマネージャに登録する必要があります。アプリ内の任意の場所で
public class ThreadManager {
private ArrayList<CustomService> services;
/**
* Constructor
*/
public ThreadManager() {
services = new ArrayList<CustomService>();
}
/**
* Method to cancel running services
*/
public boolean cancelServices() {
for(CustomService service : services) {
if(service.isRunning()) {
((Service) service).cancel();
while(!service.isStopped()) {
// Wait for it to stop
}
}
}
return true;
}
/**
* Method to register a service
*/
public void registerService(CustomService service) {
services.add(service);
}
/**
* Method to remove a service
*/
public void removeService(CustomService service) {
services.remove(service);
}
}
我々は(cancelServicesを呼び出してサービスを停止する場合)。これは状態をキャンセルするように設定します私はcalculateMethod()でこれをチェックしてから、戻り直前に状態を停止に設定します(実際にスレッドを終了します)。あなたの問題へ
if(task.isCancelled()) {
service.setStopped(true);
return null;
}
デシベルになぜ複数の呼び出し? 1回のコールで必要な情報をすべて手に入れてみませんか? – Sedrick
それはDBから受け取ったものに基づいていくつかの計算を行い、その結果を使ってDBから他のものを得るためです。私は変更できないビジネスロジックです。 – user3552551
'task'が終了するまで、dbへの別の呼び出しをトリガーする' Nodes'をすべて無効にします。 – Sedrick