3

MySQL データベースから古いデータを削除するスレッドがあります。大規模なパージが発生した場合にデータベースが消費されないようにバッチで削除するため、スレッドはパージを実行し、数秒間待機してから、パージを続行するために再度呼び出します (レコードが残っている場合)。

私の問題は、パージする必要があるものに対して複数のルールを設定できるようにすることです。バッチで何も行わなかった古いシステムでは、単純に各「パージ ルール」を反復処理してクエリを実行していました。

ただし、スレッドが再びスケジュールするシステムができたArrayListので、ルールをもう削除できます。ConcurrentModificationException

ArrayList<QueryParameters>反復するがあります。パージするレコードが残っていない場合は、リストからルールを削除して、次にスレッドが実行されたときにそれが繰り返されないようにする必要があります。

リストからルールを適切に削除する方法を教えてください。ただし、CME は取得できません。ConcurrentHashMap はできると思いますが、キー > 値を保存したくありません。

コードは、より大きな Java アプリへのプラグインです。参考までに、スレッド スケジューラを使用しています。

配列リストを反復するための両方の方法、for ループと反復子の使用を試しました。

public class PurgeTask implements Runnable {

    private Prism plugin;
    private ArrayList<QueryParameters> paramList;
    private int total_records_affected = 0, cycle_rows_affected = 0;
    private int purge_tick_delay;

    /**
     * 
     * @param plugin
     */
    public PurgeTask( Prism plugin, ArrayList<QueryParameters> paramList, int purge_tick_delay ){
        this.plugin = plugin;
        this.paramList = paramList;
        this.purge_tick_delay = purge_tick_delay;
    }


    /**
     * 
     */
    public void run(){
        if(paramList.size() > 0){
            ActionsQuery aq = new ActionsQuery(plugin);
            // Execute in batches so we don't tie up the db with one massive query
            for (Iterator<QueryParameters> it = paramList.iterator(); it.hasNext(); ) {
                QueryParameters param = it.next();

                cycle_rows_affected = aq.delete(param);
                plugin.debug("Purge cycle cleared " + cycle_rows_affected + " rows.");
                total_records_affected += cycle_rows_affected;

                // If nothing (or less than the limit) has been deleted this cycle, we need to move on
                if( cycle_rows_affected == 0 || cycle_rows_affected < plugin.getConfig().getInt("prism.purge.records-per-batch") ){

                    // Log final count of cleared records
                    plugin.log("Cleared " + total_records_affected + " rows from the database. Using:" + param.getOriginalCommand() );
                    total_records_affected = 0;

                    // Remove the purge rule from the list so we don't repeat
                    paramList.remove(param);

                } else {

                    // Items we're deleted. Leave params in queue and re-schedule this task
                    plugin.deleteTask = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new PurgeTask( plugin, paramList, purge_tick_delay ), purge_tick_delay);

                }
            }
        }
    }
}
4

1 に答える 1

1

ArrayList、それを同時に変更する可能性のある複数のスレッドによって繰り返されます。パージ タスクを同時に実行したくない場合は、ArrayListアクセスを同期できます。

public void run {
   synchronized(paramList) {
       ...
   }
}

同時実行性が必要な場合、これに適したデータ構造は、反復処理中にリストの整合性を保証するCopyOnWriteArrayListになりますが、削除操作はよりコストがかかります。リスト全体へのアクセスを同期するよりも効率的です。

さらに、次のList.remove()メソッドでパラメータを削除する必要があります。paramList(remove);イテレータ操作は ではサポートされていませんCopyOnWriteArrayList

PurgeTaskまた、実装ではなく、クラスでインターフェイスを使用する方が適切Listです。バックグラウンドでデータ構造を変更する方が簡単です。

于 2013-03-28T22:00:56.263 に答える