Pergunta

Eu tenho algumas perguntas sobre o uso e significado da palavra-chave synchronized.

  • Qual é o significado da palavra-chave synchronized?
  • Quando devem métodos ser synchronized?
  • O que significa programaticamente e logicamente?
Foi útil?

Solução

A palavra-chave synchronized é tudo sobre diferentes tópicos leitura e escrita para as mesmas variáveis, objetos e recursos. Este não é um assunto trivial em Java, mas aqui está uma citação de Sun:

métodos synchronized permitir que um simples estratégia para prevenir fio interferência e memória consistência erros: se um objeto é visível mais de um segmento, todos lê ou escreve a variáveis ??daquele objeto são feito através de métodos sincronizados.

Em um muito, muito pequeno resumo: Quando você tem dois segmentos que são leitura e escrita para o mesmo 'recurso', disse uma variável chamada foo, você precisa garantir que esses segmentos acessar o variável de uma maneira atômica. Sem a palavra-chave synchronized, seu segmento 1 não podem ver o histórico da mudança 2 feita para foo, ou pior, pode ser apenas metade alterado. Este não seria o que logicamente esperar.

Mais uma vez, este é um tema não-trivial em Java. Para saber mais, explorar temas aqui no SO ea Interwebs sobre: ??

Mantenha explorar estes tópicos até que o nome "Brian Goetz" se torna permanentemente associado ao termo "simultaneidade" em seu cérebro.

Outras dicas

Bem, eu acho que nós tivemos o suficiente de explicações teóricas, por isso considero este código

public class SOP {
    public static void print(String s) {
        System.out.println(s+"\n");
    }
}

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;
    public TestThread(String name,TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }
    @Override
    public void run() {
        theDemo.test(name);
    }
}

public class TheDemo {
    public synchronized void test(String name) {
        for(int i=0;i<10;i++) {
            SOP.print(name + " :: "+i);
            try{
                Thread.sleep(500);
            } catch (Exception e) {
                SOP.print(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1",theDemo);
        new TestThread("THREAD 2",theDemo);
        new TestThread("THREAD 3",theDemo);
    }
}

Nota: chamada blocos synchronized do próximo segmento para teste () método, desde que a execução do segmento anterior é não terminou. Threads podem acessar este método um de cada vez. Sem synchronized os tópicos podem acessar este método ao mesmo tempo.

Quando um thread chama o método sincronizado 'teste' do objeto (aqui objeto é uma instância da classe 'TheDemo') que adquire o bloqueio desse objeto, qualquer novo segmento não pode chamar o método QUALQUER sincronizada do mesmo objeto, contanto como fio anterior, que tinha adquirido o bloqueio não liberar o bloqueio.

Semelhante coisa acontece quando qualquer método estático sincronizada da classe é chamado. O fio adquire o bloqueio associado com a classe (neste caso qualquer método não estática de uma instância da classe que sincronizada pode ser chamada por qualquer segmento porque esse bloqueio nível objecto ainda está disponível). Qualquer outro segmento não será capaz de chamar qualquer método estático sincronizada da classe, desde que o bloqueio de nível de classe não é liberado pelo segmento que atualmente mantém o bloqueio.

saída com sincronizados

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

saída sem sincronizados

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9

A palavra-chave synchronized impede o acesso simultâneo a um bloco de código ou objeto por vários segmentos. Por padrão, um Hashtable é synchronized, portanto, apenas um thread pode acessar a tabela de cada vez.

No uso de construções non-synchronized como HashMap, você deve construir características de segurança segmento em seu código para evitar erros de consistência de memória.

meios synchronized que em um ambiente multi roscado, um objecto tendo método synchronized (s) / bloco (s) não permite que dois fios para o acesso a método synchronized (s) / bloco (s) de código, ao mesmo tempo. Isto significa que um segmento não pode ler enquanto outra thread atualiza-lo.

O segundo segmento será em vez esperar até o primeiro segmento concluir sua execução. A sobrecarga é a velocidade, mas a vantagem é garantida consistência de dados.

Se o seu aplicativo é única embora rosca, blocos synchronized não fornece benefícios.

A palavra-chave synchronized faz com que um fio para se obter um bloqueio ao entrar no método, de modo que apenas um segmento pode executar o método, ao mesmo tempo (para o dado instância de objecto, a menos que seja um método estático).

Este é frequentemente chamado de fazer a classe thread-safe, mas eu diria que este é um eufemismo. Embora seja verdade que a sincronização protege o estado interno do Vector de ficar corrompido, isso não costuma ajudar o usuário de Vector muito.

Considere o seguinte:

 if (vector.isEmpty()){
     vector.add(data);
 }

Embora os métodos envolvidos são sincronizados, uma vez que estão a ser bloqueado e desbloqueado individualmente, dois segmentos infelizmente cronometrados pode criar um vector com dois elementos.

Então, na verdade, você tem que sincronizar no código do aplicativo também.

Como a sincronização em nível de método é a) caro quando você não precisa dele e b) insuficiente quando você precisa de sincronização, agora existem substitutos un-sincronizado (ArrayList no caso de Vector).

Mais recentemente, o pacote de simultaneidade foi lançado, com um número de utilitários inteligentes que cuidam de questões multi-threading.

Visão geral

Synchronized palavra-chave em Java tem a ver com thread-segurança, isto é, quando vários segmentos ler ou escrever a mesma variável.
Isto pode acontecer diretamente (acessando a mesma variável) ou indiretamente (usando uma classe que usa outra classe que acessa a mesma variável).

A palavra-chave sincronizado é usado para definir um bloco de código onde vários segmentos podem acessar a mesma variável de uma forma segura.

Deeper

Syntax-wise a palavra-chave synchronized leva uma Object como parâmetro (chamado um objeto de bloqueio ), que é seguida por um { block of code }.

  • Quando a execução encontra esta palavra-chave, as tentativas segmento atual "lock / aquisição / própria" (faça a sua escolha) a Bloqueio objeto e executar o bloco associado de código após o bloqueio tem foram adquiridos.

  • Qualquer gravações variáveis ??dentro do bloco de código sincronizado são garantidos para ser visível para todos os outros segmento que semelhante executa o código dentro de um bloco de código sincronizado usando o mesmo objeto de bloqueio .

  • Apenas um thread por vez pode manter o bloqueio, durante o qual todos os outros tópicos que tentam adquirir o mesmo Bloqueio objeto irá esperar (pausar sua execução). O bloqueio será liberado quando a execução sai do bloco de código sincronizado.

métodos sincronizados:

Adicionando chave synchronized para uma definição do método é igual a todo o corpo do método a ser enrolado num bloco de código sincronizado com o objeto de bloqueio sendo this (para os métodos de instância) e ClassInQuestion.getClass() (para métodos de classe) .

- método de instância é um método que não tem static palavra-chave
. -. Método de classe é um método que tem palavra-chave static

Técnica

Sem sincronização, não é garantido que a ordem em que o lê e escreve acontecer, possivelmente deixando a variável com o lixo.
(Por exemplo, uma variável pode acabar com metade dos bits escritos por um fio e metade dos bits escritos por outro segmento, deixando a variável em um estado que nenhum dos tópicos tentaram escrever, mas uma bagunça combinado de ambos.)

Não é suficiente para completar uma operação de gravação em um segmento antes (tempo de relógio de parede) outra thread lê-lo, porque o hardware poderia ter em cache o valor da variável, e o segmento de leitura iria ver o valor em cache em vez do que foi escrito para ele.

Conclusão

Assim, no caso do Java, você tem que seguir o modelo de memória Java para garantir que os erros de threading não acontecem.
Em outras palavras:. Use sincronização, operações atômicas ou classes que os utilizam para você sob os capuzes

Fontes

http://docs.oracle.com/javase/specs/jls/se8 /html/index.html
Java® Specification Language, 2015/02/13

Pense nisso como uma espécie de torniquete como você pode encontrar em um campo de futebol. Há vapores paralelas de pessoas querendo chegar, mas na catraca eles estão 'sincronizado'. Somente uma pessoa por vez pode passar. Todos aqueles que querem passar vai fazer, mas eles podem ter que esperar até que eles possam passar.

O que é a palavra-chave sincronizado?

Threads comunicar principalmente através da partilha de acesso aos campos e os objetos de referência campos referem. Esta forma de comunicação é extremamente eficiente, mas faz dois tipos de erros possíveis: interferência fio e erros de consistência de memória . A ferramenta necessária para evitar esses erros é a sincronização.

blocos sincronizados ou métodos impede a interferência fio e se certificar de que os dados são consistentes. Em qualquer ponto do tempo, apenas um thread pode acessar um bloco sincronizado ou método ( seção crítica ) através da aquisição de um bloqueio. Outro segmento (s) irá esperar por liberação de bloqueio para o acesso seção crítica .

Quando são métodos sincronizados?

Os métodos são sincronizados quando você adiciona synchronized a definição do método ou declaração. Você também pode sincronizar um bloco de código específico com em um método.

O que significa pro gramaticalmente e logicamente?

Isso significa que o acesso apenas um thread pode seção crítica através da aquisição de um bloqueio. A menos que esta discussão liberar esse bloqueio, todos os outros thread (s) terá que esperar para adquirir um bloqueio. Eles não têm acesso para entrar seção crítica com a aquisição de bloqueio.

Isto não pode ser feito com uma magia. É da responsabilidade do programador para identificar seção crítica (s) na aplicação e guarde-as em conformidade. Java fornece uma estrutura para proteger a sua aplicação, mas onde e que todas as seções para ser guardado é de responsabilidade do programador.

Mais detalhes de documentação java página

Intrínseca Locks e sincronização:

A sincronização é construída em torno de uma entidade interna conhecida como o bloqueio intrínseco ou bloqueio monitor. fechaduras intrínsecas desempenhar um papel em ambos os aspectos de sincronização: fazer cumprir acesso exclusivo ao estado de um objeto e estabelecer acontece-antes de relacionamentos que são essenciais para a visibilidade

.

Cada objeto tem um bloqueio intrínseco associado com ele . Por convenção, um segmento que precisa de acesso exclusivo e consistente para campos de um objeto tem de adquirir bloqueio intrínseca do objeto antes de acessá-los, e, em seguida, liberar o bloqueio intrínseca quando ele é feito com eles.

Uma linha é dito que possui o bloqueio intrínseca entre o tempo que adquiriu o bloqueio e liberado o bloqueio. Enquanto um segmento possui um bloqueio intrínseco, nenhuma outra thread pode adquirir o mesmo bloqueio. O outro segmento vai bloquear quando tenta adquirir o bloqueio.

Quando um thread libera um bloqueio intrínseco, um acontece-antes de relação é estabelecida entre essa ação e qualquer posterior aquisição do mesmo bloqueio.

Fazendo métodos sincronizados tem dois efeitos :

Em primeiro lugar, não é possível para dois invocações de métodos sincronizadas no mesmo objecto a intercalação.

Quando uma linha é a execução de um método sincronizado para um objecto, todos os outros segmentos que invocar métodos para o mesmo bloco de objecto (suspender a execução) sincronizadas, até que o primeiro segmento é feito com o objeto.

Em segundo lugar, quando um sincronizados saídas método, ele automaticamente estabelece uma acontece-antes de relacionamento com qualquer invocação posterior de um método sincronizado para o mesmo objeto.

Isso garante que alterações no estado do objeto são visíveis para todos os tópicos.

procurar outras alternativas para sincronização em:

Evite sincronizado (this) em Java?

Aqui está uma explicação de O Java Tutoriais .

Considere o seguinte código:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

se count é um exemplo de SynchronizedCounter, em seguida, fazendo estes métodos sincronizados tem dois efeitos:

  • Em primeiro lugar, não é possível que duas invocações de métodos sincronizados no mesmo objeto para intercalar. Quando uma linha é a execução de um método sincronizado para um objecto, todos os outros segmentos que invocar métodos para o mesmo bloco de objecto (suspender a execução) sincronizadas, até que o primeiro segmento é feito com o objeto.
  • Em segundo lugar, quando um sincronizados saídas método, ele automaticamente estabelece uma acontece-antes de relacionamento com qualquer invocação posterior de um método sincronizado para o mesmo objeto. Isso garante que alterações no estado do objeto são visíveis para todos os tópicos.

Synchronized normal method ao equivalente Synchronized statement (usar este)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static method equivalente a Synchronized statement (classe de uso)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

declaração sincronizado (usando variável)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

Para synchronized, temos tanto Synchronized Methods e Synchronized Statements. No entanto, Synchronized Methods é semelhante ao Synchronized Statements por isso, só precisa entender Synchronized Statements.

=> Basicamente, teremos

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

Aqui está 2 pensar que ajuda a compreensão synchronized

  • Cada objeto / classe têm um intrinsic lock associado a ele.
  • Quando um thread invoca um synchronized statement, adquire automaticamente o intrinsic lock para esse objeto synchronized statement's e libera-lo quando o método retorna. Enquanto um segmento possui um intrinsic lock, NÃO outro thread pode adquirir o MESMO lock => thread-safe.

=> Quando um thread A invoca synchronized(this){// code 1} => todo o código de bloco (classe interior) onde tem synchronized(this) e todos synchronized normal method (dentro classe) está bloqueado, porque MESMO bloqueio. Ele irá executar após desbloqueio thread A ( "// código 1" acabado).

Este comportamento é semelhante ao synchronized(a variable){// code 1} ou synchronized(class).

mesmo bloqueio => bloqueio (não depender de qual método? Ou que declarações?)

Usar declarações método sincronizados ou sincronizados?

Eu prefiro synchronized statements porque é mais extensível. Exemplo, no futuro, você só precisa sincronizado uma parte do método. Exemplo, você tem 2 método sincronizado e não têm qualquer relevantes para o outro, no entanto, quando um fio de executar um método, ele irá bloquear o outro método (ele pode impedir pelo uso synchronized(a variable)).

método No entanto, aplicar sincronizado é simples eo código simples olhar. Para alguma classe, há método só 1 sincronizado, ou todos os métodos sincronizados na classe em relevantes para cada outras => podemos usar synchronized method para tornar o código mais curto e fácil de entender

Nota

(não relevante para muito para synchronized, é a diferença entre objeto e classe ou nenhum-estático e estático).

  • Quando você usa synchronized ou método normal ou synchronized(this) ou synchronized(non-static variable) será sincronizado de base em cada instância do objeto.
  • Quando você usa synchronized ou método estático ou synchronized(class) ou synchronized(static variable) será sincronizado base sobre a classe

Referência

https://docs.oracle.com/javase/tutorial/ essencial / simultaneidade / syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency /locksync.html

Hope isso ajuda

Para o meu entendimento sincronizado basicamente significa que a gravação compilador um Monitor.Enter e monitor.exit em torno de seu método. Como tal, pode ser thread-safe, dependendo de como ele é usado (o que quero dizer é que você pode escrever um objeto com métodos sincronizados que não é threadsafe, dependendo do que sua classe faz).

O que as outras respostas estão faltando é um aspecto importante: barreiras de memória . sincronização de threads consiste basicamente de dois partes: a serialização e visibilidade. Aconselho a todos a Google por "barreira de memória JVM", pois é um tópico não-trivial e extremamente importante (se você modificar os dados compartilhados acessados ??por múltiplos threads). Tendo feito isso, eu aconselho a olhar para as classes do pacote java.util.concurrent que ajudam a evitar o uso de sincronização explícita, que por sua vez ajuda a manter programas simples e eficiente, talvez até mesmo evitar conflitos.

Um exemplo é ConcurrentLinkedDeque . Juntamente com o href="https://en.wikipedia.org/wiki/Command_pattern" rel="noreferrer"> padrão de comando permite criar segmentos de trabalho altamente eficientes enchendo os comandos na fila simultânea -. necessário, há impasses possível nenhuma sincronização explícita, sem dormir explícita () necessário, apenas sondar a fila chamando take ()

Em suma: "sincronização de memória" acontece implicitamente quando você iniciar uma discussão, um segmento termina, você leu uma variável volátil, você desbloquear um monitor (deixar um bloco / função sincronizado) etc. Esta "sincronização" afeta (em um sentido "flushes") todas escreve feito antes que a ação particular. No caso do referido ConcurrentLinkedDeque , a documentação "diz":

Memória efeitos de consistência: Tal como acontece com outras coleções simultâneas, as acções de um encadeamento antes da colocação de um objecto numa ConcurrentLinkedDeque acontecer, antes ações subsequentes ao acesso ou remoção do referido elemento do ConcurrentLinkedDeque noutro fio.

Este comportamento implícito é um aspecto um pouco perniciosa porque a maioria dos programadores Java sem muita experiência só vai ter um monte como dado por causa disso. E, de repente tropeçar esta discussão após o Java não está fazendo o que é "suposto" para fazer na produção, onde há uma carga de trabalho diferente -. E é muito difícil de questões de teste de simultaneidade

sincronizada significa simplesmente que múltiplos threads se associados único objeto pode impedir leitura suja e escrita se bloco sincronizado é usado em particular, objeto. Para lhe dar mais clareza, vamos dar um exemplo:

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

Nós criamos dois objetos de classe MyRunnable, runnable1 sendo compartilhados com a linha 1 e linha 3 & runnable2 sendo compartilhado com apenas rosca 2. Agora, quando T1 e T3 inicia sem sincronizada sendo usado, a saída PFB que sugerem que ambas as linhas 1 e 3 simultaneamente afetando valor var onde para a linha 2, var tem sua própria memória.

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

Usando Synchronzied, passe 3 esperando por fio 1 para completar em todos os cenários. Há dois bloqueios adquiridos, um em runnable1 compartilhada pela linha 1 e linha 3 e outro no runnable2 compartilhada pela linha 2 apenas.

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18

meios simples sincronizados nenhuma dois fios pode aceder ao bloco / método simultâneo. Quando dizemos que qualquer bloco / método de uma classe é sincronizado isso significa apenas uma thread pode acessá-los de uma vez. Internamente, a discussão que tenta acessá-lo ter um primeiro bloqueio no objeto e enquanto esse bloqueio não está disponível nenhuma outra thread pode acessar qualquer um dos sincronizados métodos / blocos de que instância da classe.

Nota outro segmento pode aceder a um método do mesmo objecto que não está definida para ser sincronizado. Um thread pode liberar o bloqueio chamando

Object.wait()

sincronizado é uma palavra-chave em Java que é usado para fazer acontecer antes de relacionamento no multithreading ambiente à inconsistência memória evitar e erro interferência fio.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top