Uso simples do sincronizador de fila AQS AbstractQueuedSynchronizer

 O sincronizador de fila AbstractQueuedSynchronizer é usado para construir uma estrutura básica para bloqueios ou outros componentes de sincronização.Ele usa uma variável de membro int para representar o status de sincronização e completa o enfileiramento de threads de aquisição de recursos por meio da fila FIFO embutida. Podemos examinar o código-fonte de bloqueios reentrantes, bloqueios de leitura e gravação ou semáforos, CountDownLatch e outras fontes apresentadas anteriormente. Você descobrirá que sempre há uma classe interna estática em seu código-fonte que herda AbstractQueuedSynchronizer. O exemplo de código é o seguinte:

static class Sync extends AbstractQueuedSynchronizer {
    //具体逻辑
}

A principal maneira de usar o sincronizador é a herança. As subclasses gerenciam o estado de sincronização herdando o sincronizador e implementando seus métodos abstratos. Em AbstractQueuedSynchronizer, há um estado variável que identifica o estado de sincronização e fornece getState (), setState (int newState) e compareAndSetState (int expect, int update)) Três métodos para operar o estado síncrono. Eles podem garantir que a mudança de estado é segura.

O sincronizador é projetado com base no padrão de método de modelo, ou seja, o usuário precisa herdar o sincronizador e reescrever o método especificado, em seguida, combinar o sincronizador na implementação do componente de sincronização personalizado e chamar o método de modelo fornecido pelo sincronizador. E esses métodos de modelo chamarão o método substituído pelo usuário. A seguir está o método de modelo fornecido pelo sincronizador:

Nome do método

Descrição

void adquirir (int arg)

Aquisição exclusiva do status de sincronização, se a thread atual adquirir o status com sucesso, este método retornará, caso contrário, ele entrará na fila de sincronização para esperar, este método irá chamar o método tryAcquire (iny arg) substituído

void absorbInterruptibly (int arg)

O mesmo que adquirir (int arg), mas este método responderá à interrupção. O thread atual não obtém o status de sincronização e entra na fila de sincronização. Se o thread atual for interrompido, um InterruptedException será lançado.

 

boolean tryAcquireNanos (int arg, long nanos)

O limite de tempo limite é aumentado com base em takeInterruptibly (int arg). Se o estado de sincronização não for obtido dentro do tempo especificado, ele retornará falso, caso contrário, retornará verdadeiro.

 

void absorbShare (int arg)

A diferença entre o acesso compartilhado ao status de sincronização e o acesso exclusivo é que vários threads podem obter o status de sincronização ao mesmo tempo. Irá chamar o método rewrite tryAcquireShared

void activateShareInterruptibly (int arg)

O mesmo que adquirirShare (int arg), mas este método responderá à interrupção

boolean tryAcquireSharedNanos (int arg, long nanos)

O limite de tempo limite é aumentado com base em takeShareInterruptibly (int arg). Se o estado de sincronização não for obtido dentro do tempo especificado, ele retornará falso, caso contrário, retornará verdadeiro.

lançamento booleano (int arg)

Liberar exclusivamente o estado de sincronização. Este método irá despertar o thread contido no primeiro nó na fila de sincronização após liberar o estado de sincronização. Chamará o método rewrite tryRelease

boolean releaseShared (int arg)

Estado de sincronização de liberação compartilhada, chamará o método de substituição tryReleaseShared

Coleção <Thread> getQueueThreads ()

Obtenha a coleção de tópicos na fila de espera

Como dissemos antes, o método do modelo será chamado e substituiremos o método substituído. Vamos dar uma olhada nos métodos fornecidos pelo sincronizador que precisamos substituir. A tabela a seguir mostra os métodos que o sincronizador pode substituir:

Nome do método

Descrição

protected boolean tryAcquire (int arg)

Obtenha o status de sincronização exclusivamente. Para implementar este método, você precisa consultar o status atual e determinar se o status de sincronização atende às expectativas, e então executar CAS para definir o status de sincronização

protected boolean tryRelease (int arg)

Liberar exclusivamente o estado de sincronização, threads aguardando para obter o estado de sincronização terão a oportunidade de obter o estado de sincronização

protegido int tryAcquireShared (int arg)

Acesso compartilhado ao status de sincronização, retorna um valor maior que 0 para indicar sucesso, caso contrário, a aquisição falha.

protected boolean tryReleaseShared (int arg)

Estado de sincronização de liberação compartilhada.

protegido booleano isHeldExclusively ()

Se o sincronizador atual está ocupado por uma thread em modo exclusivo, geralmente este método indica se ele está ocupado exclusivamente pela thread atual

Acima, apresentamos o método de modelo e o método regravável do sincronizador. A partir do método, podemos ver que os métodos de modelo fornecidos pelo sincronizador são basicamente divididos em três categorias: aquisição exclusiva e estado de sincronização de liberação, aquisição compartilhada e estado de sincronização de liberação e sincronização de consulta O status de threads em espera na fila. O componente de sincronização personalizado usará o método de modelo fornecido pelo sincronizador para implementar sua própria semântica de sincronização. O seguinte usará um exemplo de bloqueio exclusivo para aprender mais sobre o uso de sincronizadores. Em primeiro lugar, nosso último modelo, semelhante às ferramentas fornecidas pelo JUC, escreve um sincronizador de herança de classe interna.

public class MutexLock{
    private final Sync sync = new Sync();
    //内部类继承同步器
    private static class Sync extends AbstractQueuedSynchronizer {
	private static final long serialVersionUID = 1L;
    }
    //获取锁
    public void lock() {
    }
    //可中断获取锁
    public void lockInterruptibly() throws InterruptedException {
    }
    //尝试获取锁
    public boolean tryLock() {
	return false;
    }
    //可超时尝试获取锁
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
	return false;
    }
    //释放锁
    public void unlock() {
    }
}

Conforme mostrado no código acima, é um modelo escrito sem qualquer implementação e, abaixo, precisamos usar o método de modelo fornecido pelo sincronizador e o método regravável para obter o bloqueio exclusivo acima. Este é apenas um exemplo simples de aprendizagem. Depois de aprender o princípio de realização do sincronizador, ferramentas de sincronização mais complexas serão escritas. Orientamos o sincronizador através do método de modelo acima para fornecer três métodos para adquirir bloqueios e um método para liberar bloqueios. Podemos implementar o seguinte código lógico da seguinte maneira:

public class MutexLock{
    private final Sync sync = new Sync();
    private static class Sync extends AbstractQueuedSynchronizer {
	private static final long serialVersionUID = 1L;
    }
    public void lock() {
	//调用同步器的方法获取锁
	sync.acquire(1);
    }
    public void lockInterruptibly() throws InterruptedException {
	//调用同步器的方法可中断获取锁
	sync.acquireInterruptibly(1);
    }
    public boolean tryLock() {
	return false;
    }
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        //默认传入的是nanoseconds,不再做时间的转换
        return sync.tryAcquireNanos(1, time);
    }
    public void unlock() {
        //调用同步器的方法释放锁
        sync.release(1);
    }
}

Anteriormente, dissemos que void occur (int arg) chamará o método reescrito tryAcquire (iny arg), portanto, precisamos reescrever o método tryAcquire (iny arg) para alterar o estado do sincronizador. Se tiver êxito, adquira o bloqueio. Se falhar, adicione-o à fila de espera. A implementação do código a seguir.

private static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 1L;
    public boolean tryAcquire(int acquires) {
        //如果将状态改变为1,如果成功则获取到锁
	if (compareAndSetState(0, 1)) {
	    setExclusiveOwnerThread(Thread.currentThread());
	    return true;
	}
        return false;
    }
    //释放锁
    protected boolean tryRelease(int releases) {
        if (getState() == 0)
            throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
    }
}

Este blog é principalmente para explicar o uso básico do sincronizador AbstractQueuedSynchronizer e para entender os métodos de modelo e métodos regraváveis ​​fornecidos por AbstractQueuedSynchronizer. Podemos usar AbstractQueuedSynchronizer para construir rapidamente um componente de sincronização. Analisaremos o princípio de implementação de AbstractQueuedSynchronizer em detalhes posteriormente.

Acho que você gosta

Origin blog.csdn.net/wk19920726/article/details/108322547
Recomendado
Clasificación