Spring Boot потокобезопасный, похожий на карту класс для хранения именованных значений в файле - PullRequest
0 голосов
/ 26 мая 2020

Чтобы удовлетворить требование иметь одно или несколько простых именованных значений (например, String или int), которые сохраняются после перезапуска службы Spring Boot, я создал следующий класс, который будет использоваться только для некритических значений ( в противном случае база данных - лучший вариант).

Пример использования - приращение счетчика, используемого для подсчета отправленных писем:

    public int getAndIncreaseLogsCount() throws IOException, FileNotFoundException, ClassNotFoundException {
        int count = Preferences.get("logsCounter", 0);
        Preferences.set("logsCounter", ++count);
        return count;
    }

Мой вопрос в том, действительно ли мой код является потоком -сейф. Спасибо за подсказки.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Thread-safe map-like class to store named values in a file.
 */
public class Preferences {

    private static final Map<String, String> map = new ConcurrentHashMap<>();
    private static final Logger log = LoggerFactory.getLogger(Preferences.class);

    private synchronized static void savePreferences() throws FileNotFoundException, IOException {
        FileOutputStream f = new FileOutputStream(new File(System.getProperty("user.home") + File.separator + "myPreferences"));
        ObjectOutputStream o = new ObjectOutputStream(f);

        // Write ConcurrentHashMap to file
        o.writeObject(map);

        o.close();
        f.close();

        // log.debug("Preferences saved successfully");
    }

    private synchronized static void readPreferences() throws FileNotFoundException, IOException, ClassNotFoundException {
        File file = new File(System.getProperty("user.home") + File.separator + "myPreferences");
        if (!file.exists()) {
            log.warn("Preferences cannot be read, because the file doesn't exist");
            return;
        }
        FileInputStream fi = new FileInputStream(file);
        ObjectInputStream oi = new ObjectInputStream(fi);

        // Read map
        Map<String, String> readMap = (Map<String, String>) oi.readObject();
        map.clear();
        map.putAll(readMap);

        oi.close();
        fi.close();

        // log.debug("Preferences read successfully");
    }

    static {
        try {
            readPreferences();
        } catch (IOException | ClassNotFoundException ex) {
            log.error(ex.getMessage());
        }
    }

    public synchronized static void set(String name, int value) throws IOException {
        map.put(name, value + "");
        savePreferences();
    }

    public synchronized static void set(String name, String value) throws IOException {
        map.put(name, value);
        savePreferences();
    }

    public synchronized static int get(String name, int def) throws IOException, FileNotFoundException, ClassNotFoundException {
        if (map.isEmpty()) {
            readPreferences();
        }
        String value = map.get(name);
        if (value == null) {
            return def;
        } else {
            return Integer.valueOf(value);
        }
    }

    public synchronized static String get(String name, String def) throws IOException, FileNotFoundException, ClassNotFoundException {
        if (map.isEmpty()) {
            readPreferences();
        }
        String value = map.get(name);
        if (value == null) {
            return def;
        } else {
            return value;
        }
    }
}
...