Initialize and change static variable in a thead safe way. Does this code make sense? Intellij IDEA doesn’t think

Asked

Viewed 145 times

2

Hello!

I’m looking for a safe way to boot and change a static variable that will be shared by different threads that will be accessing its value.

The idea is that, at some point, I will verify that this variable needs to be changed and I want your change to be thread safe, without affecting the threads that are accessing your current value.

The ideal was not to make the treads stop to wait for the update, because the current value is still valid.

I’m using the variable in a Component (@Service) Spring, so you can call the services.

The code below shows the current solution. Basically, it is a class for other classes to always take the updated token, making the first authentication if the token is null or renewing the token if it is close to expire.

Current code (not yet tested):

@AllArgsConstructor
@Service
public class TokenService {

    private static TokenData TOKEN = null;

    private final LoginService loginService;
    private final RefreshTokenService refreshTokenService;

    public String getToken() {

        if (TOKEN == null) {
            synchronized (TOKEN) {
                // preciso verificar novamente se está nulo, pois pode ter ocorrido de uma outra thread ter inicializado já o Token
                if (TOKEN == null) {
                    TOKEN = autenticar();
                }
            }
        }
        return obterToken();
    }

    private TokenData autenticar() {
        AutenticacaoResponse autenticacaoResponse = loginService.autenticar();
        return new TokenData(autenticacaoResponse.getAuthToken(), autenticacaoResponse.getIssuedAt());
    }

    private String obterToken() {
        if (isPertoExpirar()) {
            synchronized (TOKEN) {
                // preciso verificar novamente se está perto de expirar, pois pode ter ocorrido de uma outra thread ter já alterado o Token. 
                // Aqui eu até poderia abrir mão deste controle, pois não teria problema se duas ou mais threads chamassem o refresh.
                if (isPertoExpirar()) {
                    AutenticacaoResponse autenticacaoResponse = refreshTokenService.atualizar(TOKEN.getToken());
                    TOKEN = new TokenData(autenticacaoResponse.getAuthToken(), autenticacaoResponse.getIssuedAt());
                }
            }
        }
        return TOKEN.getToken();
    }

    private boolean isPertoExpirar() {
        return TOKEN.isFaltaMeiaHoraExpirar();
    }
}

My idea was to put a syncronized in the variable TOKEN, but the Intellij IDEA warning of two problems while trying to do this:

Dereference of 'TOKEN' may produce java.lang.NullPointerException
Synchronization of a non-final field 'TOKEN'

I could try to initialize the class TokenData and know if there is a valid token inside it, but still would be receiving the second alert. I don’t see much problem with this, but according to the Intellij IDEA:

Reports Synchronized statements Where the lock Expression is a Reference to a non-final field. Such statements are unlikely to have Useful Semantics, as Different threads may be Locking on Different Objects Even when Operating on the same Object.

1 answer

2


Do not Sincronize on the token. Sync on a final object.

private static final Object lock = new Object();

synchronized (lock) {
    ...
}

Browser other questions tagged

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