Чтобы удовлетворить требование иметь одно или несколько простых именованных значений (например, 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;
}
}
}