私は頻繁に変更されるのArrayListの値を格納し、アプリケーションがクラッシュした場合には、それらの値を保持する必要があります。それは良い選択のように思えたので、アプリケーションは、私は、すでに用途にRedisのデータベースを働いています。
以下、IはRedisのローカルホストのインスタンスに接続し、使用、それをシリアル化オブジェクトを格納することがスプリングブートコントローラの最小の例を煮詰めました。値は、コントローラのエンドポイントから、または5秒ごとに実行されるスケジュールされたジョブを使用して変更することができます。あなたがするには、Get-一連の要求を行う場合はlocalhost:8080/test
、一度に1のArrayListからスケジュールジョブ削除項目が表示されます。
それは価値が逃した、またはスレッドセーフではない何かがここで発生するために取得することは可能ですか?私は、彼らはネットワークが遅くなる場合は特に、オブジェクトを同時に変更またはRedisの値を設定しようとすると、コントローラのエンドポイントからの変更内容とスケジュールされたジョブのかもしれないの競合を懸念していますが、それは実際になるかどうかはわかりませんよ問題。それは私のローカルホスト上で動作するようすべてが正常に動作するようだが、私は懐疑的。
私が読んで、このスレッドの安全性に関する他の中の記事を、しかし、それらのもののいずれかがこの特定の状況のためにも必要であるかどうかは答えませんでした。私はまたことを承知しているRedisの読み取りおよび書き込みはアトミックですが、私はコマンドが誤った順序でのRedisに送信されますどのような場合には、思いましたか?
私はこの実装に問題がある場合は、ロンボク島の@Syncronized注釈がIOのための抽象化方法のために有用であるかもしれないと考えていました。私が過ごした任意の入力と時間を感謝しています。
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
@RestController
public class Example {
RedisClient redisClient = RedisClient.create("redis://localhost:6379/");
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> redis = connection.sync();
Gson gson = new Gson();
ArrayList<String> someList = new ArrayList<>();
public Example() {
if(redis.exists("somekey") == 1){
Type collectionType = new TypeToken<Collection<VideoDAO>>(){}.getType();
someList = new ArrayList<>(gson.fromJson(redis.get("somekey"), collectionType));
}
}
@GetMapping("/test")
public void addToSomeList(){
someList.add("sample string");
redis.set("somekey",gson.toJson(someList));
System.out.println("New item added. " + someList.size() + " items in array");
}
@Scheduled(fixedRate = 5000)
public void popFromSomeList() {
if (!someList.isEmpty()) {
someList.remove(0);
redis.set("somekey", gson.toJson(someList));
System.out.println("Item removed. " + someList.size() + " items in array");
}
}
}
私は、java 1.8を使用しています。
ほとんど明らかにsomeList
あなたはRedisのを無視してもそれほどコードが壊れている、スレッドセーフではありません。
我々は、それがスレッドセーフで作るとしましょうCollections.synchronizedList(new ArrayList<>());
。そして、add
そしてpop
まだそのかもしれませんがいない問題が多すぎるため、アトミックではありません機能。あなただけの実行の(例えば)以下のようなもので終わる可能性
someList.add("sample string");
someList.remove(0);
redis.set("somekey", gson.toJson(someList));
redis.set("somekey", gson.toJson(someList));
それは、「新しいアイテムが追加されます。配列の4項目」を示すことができるように、とのメッセージが、混乱することができ、「新しいアイテムが追加されます。配列の4つの項目」、「アイテムを削除しました。配列の4項目」を、追加/削除が起こっによるもの印刷する前に。
だから、与えられたコード(または類似)のための適切な機能のために、あなたは、メソッドを同期または明示的な共有ロックを使用しなければならないでしょう。間違った順序でコマンドを送信する可能性がありますが、それは、同じデータの重複セットにつながるとして与えられた例(リストはスレッドセーフ作られて提供される)に本当の危険のないチャンスは、ありません。