0
I am rewriting a software that serves as a communication bridge between two services. Communication is done via sockets. The environment has high data competition, especially a list of active sockets. The software has some problems because this competition has not been handled correctly, causing some information to be shown wrong, or not delivered at a particular point of communication.
As I’m rewriting, I have some questions about the best and safest scenario.
Imagine the following thing: Multiple threads accessing a single list, can add, remove, and iterate multiple times in the same second.
To solve this problem, I created the following structure:
Serverservice (Where would be the list that would be accessed by all threads)
@Component
public class ServerService {
private CopyOnWriteArrayList<String> lista = new CopyOnWriteArrayList(new ArrayList<String>());
public void add(String string, String myThreadName){
System.out.println(myThreadName+". ADICIONANDO VALOR: "+string);
lista.add(string);
}
public void remove(String string, String myThreadName){
System.out.println(myThreadName+". REMOVENDO VALOR: "+string);
lista.remove(string);
}
void printAll(String myThreadName){
synchronized (lista){
lista.forEach(s -> System.out.println(myThreadName+". ITERANDO VALUE: "+s));
}
}
List<String> getAll(){
return lista;
}
}
Myrunnable (Where would be the control part of sockets that would add, remove or 'iterate' the list)
public class MyRunnable implements Runnable{
ServerService serverService;
String myThreadName;
@Autowired
public MyRunnable(ServerService serverService, String myThreadName) {
this.serverService = serverService;
this.myThreadName = myThreadName;
}
@Override
public void run() {
while(true){
String value = Double.toString(ThreadLocalRandom.current().nextInt(0, 10));
serverService.add(value, myThreadName);
serverService.printAll(myThreadName);
serverService.remove(value, myThreadName);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Demoapplication (Only one main to start)
@SpringBootApplication
public class DemoApplication implements ApplicationRunner {
@Autowired
ServerService serverService;
@Autowired
TaskExecutor taskExecutor;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
taskExecutor.execute(new MyRunnable(serverService, "THREAD 1"));
taskExecutor.execute(new MyRunnable(serverService, "THREAD 2"));
}
}
That way, I’ll have the right competitive behavior on the list?
Another question, how would I 'iterate' the list inside the thread, in a synchronized way, not being able to add another thread in the list when another is doing the iteration? That would be the right way?
@Override
public void run() {
while(true){
String value = Double.toString(ThreadLocalRandom.current().nextInt(0, 10));
serverService.add(value, myThreadName);
synchronized (serverService.getAll()){ --ALTERAÇÃO AQUI
serverService.getAll().stream().forEach(System.out::println);
}
serverService.remove(value, myThreadName);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
If necessary, I put more details.
Every operation in the list should be synchronized, so the add, remove, and iterate options should be synchronized. You commented from the syncronized, the
CopyOnWriteArrayList
does that job.– Cristiano Bombazar