Multithread and Data Competition + Spring

Asked

Viewed 261 times

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.

2 answers

1

Questions with thread will always depend on the scenario!

However, it is important to know a useful stop mechanism, the Synchronized. This command causes only 1 thread to be executed at the same time.

With that, we can make a list Synchronized so that it can only be modified with one thread at a time.

Use Synchronized with wisdom! It is not interesting to put it at all, can compromise your software and much.

Another way out would be to create static controls, such as thread-related id s, list and operations... But this is not the best option.

  • 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.

0

-Operations modifying list content must be Synchronized. When a Synchronized method is placed, it only allows one thread to run at a time. Hence it is important that your code is not all Synchronized because it would always be just one thread running through the code at a time. (Use/See the implementation of blocking)

-Why? For example, when you remove something from the list and decrease the size of the list (i-), let’s assume that you need 3 sub-actions to decrease the size of the list (find the value of i, decrease it and update its value), if two threads do this action at the same time it may be that while one is removing from the list, the other has already made the first two sub-actions and has not updated the new i value and will only update after the other fetch the i value which was not correct (thread would fetch an outdated value).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.