I have the following Singleton class
public class TestFileEngine {
private static int counter = 0;
private static List<GeneratedFile> generatedFileList;
private static Optional<TestFileEngine> engine = Optional.empty();
private TestFileEngine() {
generatedFileList = Collections.synchronizedList(new ArrayList<>());
}
public static synchronized TestFileEngine getInstance() {
if (!engine.isPresent()) {
engine = Optional.of(new TestFileEngine());
}
return ruEngine.get();
}
public synchronized void generateFile() {
counter++;
String timestamp = LocalDateTime.now().toString();
String content = "";//insert random content generation
GeneratedFile gf = new GeneratedFile(counter + ".txt", timestamp, content);
generatedFileList.add(gf);
System.out.println("Generated file " + counter + ".txt");
}
public GeneratedFile findFileByName(String filename) {
for (GeneratedFile file : generatedFileList){
if(file.getFileName().equals(filename)){
return file;
}
}
return null;
}
}
Now I want to have two separate engines (and possibly more in the future), for tracking purpose and I stumbled upon the multiton pattern, still using the lazy implementation. So I will change the following:
//Getting rid of Optional, as it can get funky with Maps
private static final Map<String, TestFileEngine> _engines = new HashMap<String, TestFileEngine>();
public static synchronized TestFileEngine getInstance(String key) {
if (_engines.get(key) == null) {
_engines.put(key, new TestFileEngine());
System.out.println("Create engine " + key);
}else {
System.out.println("Using engine " + key);
}
return _engines.get(key);
}
I want to be sure that each of the engines has its separate counter and file list. However after I ran the following code, it seems they share counter and list:
TestFileEngine.getInstance("http").generateFile();
TestFileEngine.getInstance("http").generateFile();
TestFileEngine.getInstance("http").generateFile();
TestFileEngine.getInstance("ftp").generateFile();
TestFileEngine.getInstance("ftp").generateFile();
System.out.println(TestFileEngine.getInstance("http").findFileByName("4.txt").getFileName());
System.out.println(TestFileEngine.getInstance("ftp").findFileByName("2.txt"));
Console:
Create engine http
Generated file 1.txt
Using engine http
Generated file 2.txt
Using engine http
Generated file 3.txt
Create engine ftp
Generated file 4.txt
Using engine ftp
Generated file 5.txt
Using engine http
4.txt
Using engine ftp
null
What should I do to the counter
and generatedFileList
fields so that each TestFileEngine
created from the Multiton is completely separated?
Actually you declare the 3 fields of the class with the static
modifier :
private static int counter = 0;
private static List<GeneratedFile> generatedFileList;
private static final Map<String, TestFileEngine> _engines = new HashMap<String, TestFileEngine>();
static
fields are shared among all instances of the current class.
You want that for engines
field.
But you don't want that for counter
and generatedFileList
fields that have to be attached to a specific instance of TestFileEngine
.
So make them instance fields instead of static
.
As a side note, int
fields are by default valued to 0
and you should avoid _
to prefix your variables that doesn't make part of the naming conventions.
So you could write :
private int counter;
private List<GeneratedFile> generatedFileList;
private static final Map<String, TestFileEngine> engines = new HashMap<String, TestFileEngine>();