JAVA threads simultâneos e tarefas sistema -1-

Java utiliza threads para executar tarefas. Coisas tarefa que iríamos simultaneidade alcançada, a tarefa pode Runnable, mobilizável para descrever a missão também se reflete no método Run em Linha, a tarefa também pode ser descrito como um segmento de execução, apenas tópicos tarefa transportadora, mas a tarefa unidade de execução.

Tarefas e conduzir o seu fio não é o mesmo, que se reflete na classe Thread java você realmente não tem qualquer controle sobre baixo nível enfiar método p java rosqueamento mecanismo de c, e fisicamente, pode ser o custo da criação de um fio alta, é necessário para salvar e gerenciá-los, de modo que, do ponto de vista da implementação, a tarefa será separado do fio faz sentido, então este será um diferentes segmentos executáveis executar em diferentes instâncias.

Isso pode nos ajudar a entender enfiar melhor reutilização de recursos e compreensão do pool de threads.

tarefa Descrição

As tarefas podem ter Runnable, mobilizável para descrever. Executável, principal diferença mobilizável é que, não mobilizável valor de retorno ; corpo da tarefa executável, além do método de execução, o corpo tarefa mobilizável é uma chamada de método.

Especificamente Executel, Descrição mobilizável descrito abaixo, ver

Runnable

TODO: código: remove aqui

public class LiftOff implements Runnable{
    protected int countDown = 10;//default
    private static int taskCount = 0;
    private final int id=taskCount++;//id 可以区分多个对象实例(注意final和上句static)
    public LiftOff(){}
    public LiftOff(int countDown){
        this.countDown=countDown;
    }
    public String status(){
        return "#"+id+"("+ (countDown>0?countDown:"LiftOff!")+").";
    }

    @Override
    public void run() {
        while(countDown-- >0){
            System.out.println(status());
            Thread.yield();//yield是对线程调度器的建议
        }
    }
}
  • Note que este id, se um único segmento cria toda rosca Liftoff, então id é único, se vários segmentos criado fio Liftoff, então pode haver múltiplos Liftoff têm o mesmo id. Que variáveis estáticas são thread-unsafe no! (Neste caso taskCount)

mobilizável

TODO: código: remove aqui

class TaskWithResult implements Callable<String> {
    private int id;

    public TaskWithResult(int id) {
        this.id = id;
    }

    @Override
    public String call() {
        return "result of TaskWithResult "+ id;
    }
}
public static void main(String[] args) {
    ExecutorService exec= Executors.newCachedThreadPool();
    ArrayList<Future<String>> results =  new ArrayList<Future<String>>(); // Future
    for(int i=0;i<1;i++)
        results.add(exec.submit(new TaskWithResult(i))); // submit
    for(Future<String> fs: results){
        try {
            System.out.println(fs.get());// get
        }catch (InterruptedException e){
            System.out.println(e);
            return;
        }catch (ExecutionException e){
            System.out.println(e);
        }finally {
            exec.shutdown();
        }
    }
}

mobilizável

  1. exigível pode ser devolvido após a conclusão de um valor que pode receber um tipo genérico, ele é usado para especificar o tipo de retorno desejada
  2. Deve ser utilizado ExecutorService.submit()para invocar que pode ser chamado, submit()o método irá produzir um objeto Futuro
  3. call () método pode ter um valor de retorno , você pode declarar uma exceção é lançada
  4. interface genérica que pode ser chamado tem limitações, na interface Callable tipos de parâmetros genéricos e call () método retorna o tipo de valor igual

interfaces de futuros

futura interface Callable representa a interface do método de valor chamada de retorno (), JAVA para o futuro fornece uma interface para FutureTask classe de implementação, os implementos classe implementação da interface e da futura interface Runnable (FutureTask percebeu RunnableFuture, RunnableFuture herdado do futuro e Runnable, sim é herança múltipla, mas a interface não é herança múltipla classe herança múltipla) pode ser usado como classe thread executável que pode passar FutureTask thread.

Métodos e precauções na utilização dos seguintes interfaces declaração:

  1. Com isDone()se o método para consultar o Futuro foi concluída.
  2. Chame o get()método para obter esse resultado
    1. Se a isDone()determinação for concluída, chamando get()um método para obter esse resultado
    2. Se o isDone()julgamento não for concluída, get()ele irá bloquear até que os resultados estão prontos
    3. ** Estratégia: ** tentativa de chamada get()antes de obter o resultado, primeira chamada com um tempo limite get(long timeout, TimeUnit unit), ou uma chamada isDone()para ver se a tarefa é concluída
  3. cancel(boolean maylnterruptltRunning): Tentando cancelar o Futuro em associação tarefa mobilizável
  4. O impacto do tempo de chamada
    1. Se a tarefa antes de iniciar a chamada, a tarefa nunca é executado
    2. Se a tarefa já começou , mayInterruptIfRunningele irá determinar se ele deve ser thread de interrupção para executar a tarefa em uma tentativa de interromper a tarefa.
    3. Se a tarefa foi concluída , a tentativa irá falhar, retornar falso
  5. Por outras razões não irá cancelar a tarefa, retorna false
  6. Impacto sobre outros métodos após o método retorna
    1. Após esse método retorna, na isDone()chamada sempre retorna true
    2. Se este método retorna true, em seguida, a chamada isCancelled()será sempre retornar true
  7. isCancelled(): Se cancelado antes da tarefa mobilizável concluída normalmente, ele retorna true

fio

Para instruções entre tópicos partilha de recursos limitados, o mecanismo de bloqueio, consulte o seguinte artigo.

Modo de criação de thread

fio de fato criação pode ser dividido em edifício convencional e pool de threads é criado , esta seção concentra-se na secção após a criação dos métodos e técnicas convencionais, consulte o pool de threads é criado.

  1. new Thread () e passar Runnable
Thread t=new Thread(new LiftOFF());
t.start();
  • start()O método irá retornar rapidamente, e não irá bloquear chamadas.
  • Uma excepção, não pode se propagar através de threads, todas as exceções devem ser tratadas internamente gerado na tarefa local
  • Alternativamente, você pode passar: FutureTask (implementos Runnable)
  1. Passe método herdado reescrita executar

TODO: código: remove aqui

public class SimpleThread extends Thread {  // extends Thread
  private int countDown = 5;
  private static int threadCount = 0;
  public SimpleThread() {
    // Store the thread name:
    super(Integer.toString(++threadCount));
    start(); // start
  }
  public String toString() {
    return "#" + getName() + "(" + countDown + "), ";
  }
  public void run() { // run
    while(true) {
      System.out.print(this);
      if(--countDown == 0)
        return;
    }
  }
  public static void main(String[] args) {
    for(int i = 0; i < 5; i++)
      new SimpleThread();
  }
} /* Output:
#1(5), #1(4), #1(3), #1(2), #1(1), #2(5), #2(4), #2(3), #2(2), #2(1), #3(5), #3(4), #3(3), #3(2), #3(1), #4(5), #4(4), #4(3), #4(2), #4(1), #5(5), #5(4), #5(3), #5(2), #5(1),
*///:~
  1. Autogerido Runnable, que é realizada dentro do segmento variável Runnable

A formulação e o sucessor direto para enfiar nenhuma diferença, mas podemos implementar interfaces herdar uma classe diferente, herdados da rosca não.

TODO: código: remove aqui

public class SelfManaged implements Runnable {
  private int countDown = 5;
  private Thread t = new Thread(this); // new thread
  public SelfManaged() { t.start(); } // start
  public String toString() {
    return Thread.currentThread().getName() +
      "(" + countDown + "), ";
  }
  public void run() { // run
    while(true) {
      System.out.print(this);
      if(--countDown == 0)
        return;
    }
  }
  public static void main(String[] args) {
    for(int i = 0; i < 5; i++)
      new SelfManaged();
  }
} /* Output:
Thread-0(5), Thread-0(4), Thread-0(3), Thread-0(2), Thread-0(1), Thread-1(5), Thread-1(4), Thread-1(3), Thread-1(2), Thread-1(1), Thread-2(5), Thread-2(4), Thread-2(3), Thread-2(2), Thread-2(1), Thread-3(5), Thread-3(4), Thread-3(3), Thread-3(2), Thread-3(1), Thread-4(5), Thread-4(4), Thread-4(3), Thread-4(2), Thread-4(1),
*///:~

** Nota: ** 2 e 3 início são chamados no construtor, o construtor de iniciar a linha poderá tornar-se muito problemática, porque outra tarefa pode começar antes do fim do construtor, o que significa os objetos de tarefa pode ser acessado em um estado instável ( : esta frase de idéias de programação, mas agora não gostou ??? TODO outra objeto)razão,

  1. Use classe rosca interna na classe code-behind

TODO: código: remove aqui

Para este tipo de texto também deve estar alerta para a situação sobre a execução de tarefas dentro do corpo do construtor.

// Using a named inner class:
class InnerThread1 {
  private int countDown = 5;
  private Inner inner;
  private class Inner extends Thread { // Inner extends Thread
    Inner(String name) {
      super(name);
      start(); // 构造器中进行start
    }
    public void run() {
      try {
        while(true) {
          print(this);
          if(--countDown == 0) return;
          sleep(10);
        }
      } catch(InterruptedException e) {
        print("interrupted");
      }
    }
    public String toString() {
      return getName() + ": " + countDown;
    }
  }
  public InnerThread1(String name) {
    inner = new Inner(name); // 构造内部类
  }
}

// Using an anonymous inner class:
class InnerThread2 {
  private int countDown = 5;
  private Thread t;
  public InnerThread2(String name) {
    t = new Thread(name) { // InnerThread2构造器中new 了一个thread
      public void run() {
        try {
          while(true) {
            print(this);
            if(--countDown == 0) return;
            sleep(10);
          }
        } catch(InterruptedException e) {
          print("sleep() interrupted");
        }
      }
      public String toString() {
        return getName() + ": " + countDown;
      }
    };
    t.start(); // 构造器中进行start
  }
}

// Using a named Runnable implementation:
class InnerRunnable1 {
  private int countDown = 5;
  private Inner inner;
  private class Inner implements Runnable {
    Thread t;
    Inner(String name) {
      t = new Thread(this, name);
      t.start();
    }
    public void run() {
      try {
        while(true) {
          print(this);
          if(--countDown == 0) return;
          TimeUnit.MILLISECONDS.sleep(10);
        }
      } catch(InterruptedException e) {
        print("sleep() interrupted");
      }
    }
    public String toString() {
      return t.getName() + ": " + countDown;
    }
  }
  public InnerRunnable1(String name) {
    inner = new Inner(name);
  }
}

// Using an anonymous Runnable implementation:
class InnerRunnable2 {
  private int countDown = 5;
  private Thread t;
  public InnerRunnable2(String name) {
    t = new Thread(new Runnable() {
      public void run() {
        try {
          while(true) {
            print(this);
            if(--countDown == 0) return;
            TimeUnit.MILLISECONDS.sleep(10);
          }
        } catch(InterruptedException e) {
          print("sleep() interrupted");
        }
      }
      public String toString() {
        return Thread.currentThread().getName() +
          ": " + countDown;
      }
    }, name);
    t.start();
  }
}

Tópico do Ciclo de Vida

(Veja no final do texto referem-se referência 1)

O estado de comutação do segmento (modelo de rosca com cinco estado discutido):

  1. Novo estado: Quando o programa usa a nova Depois de criar um segmento de palavra-chave, o segmento está em estado novo, desta vez apenas por sua JVM Aloca memória , e para inicializar o valor de suas variáveis de membro

  2. estado de pronto: quando um objeto segmento para chamar o start () depois que o método, o segmento está no estado pronto. máquina virtual Java para criar um método de pilha de chamadas e contador de programa , à espera de ser programado para ser executado

  3. ** estado de funcionamento: Se o segmento está pronto para obter o CPU, começou run () ** fio de método de execução, o fio está em execução

  4. ** estado de bloqueio: ** Depois de perder o fio condutor os recursos ocupados, entrará no estado de bloqueio (execução)

TODO: nova chamada deve adicionar um novo estado na seta

TODO: isto deve ser levado em superior e inferior dois mapas


Novos tópicos e precauções prontos

  • Quer começar a chamar thread () método imediatamente após sub-thread começa a execução , o programa pode ser usado Thread.sleep(1) para não fazer o fio atualmente em execução (thread principal) sono 1 milissegundo, 1 milissegundo é suficiente, porque vai CPU ocioso dentro de 1 milissegundo, que iremos para executar outro segmento no estado de pronto, para que possa fazer o segmento de criança começa a execução imediatamente.
  • método de execução eo método de início : Iniciar os tópicos método start () método, em vez de run (). Nunca chamar o método do objeto segmento run (). Chamada de método start0 para iniciar uma discussão, o sistema irá executar método () como um segmento de execução ao punho, mas se o segmento de chamada executado diretamente pelo método de objeto (), método run () será executada imediatamente, mas também na corrida ( ) antes de o método retorna outros segmentos não é possível executar concorrentemente. Em outras palavras, o objeto thread do sistema como um objeto comum, e o método run () é um método comum, ao invés do segmento de execução. Note-se que, depois de chamar o método do fio run (), o fio não está mais no novo estado é, não chamar o método do objeto segmento start () novamente. Somente início call () em um segmento no novo método de estado, caso contrário ele irá levar a exceção IllegaIThreadStateException.

fio de caso no estado bloqueado

  1. chamadas de Tópicos sleep () método desistir do processador recursos ocupada pela tarefa para dormir, neste caso, a tarefa não será executado dentro de um prazo especificado. (Desbloquear: sono () método especificado tempo decorrido)
  2. Segmento chama um método IO bloqueio , na conclusão de espera de alguma entrada e de saída , antes de o retorno do método, o fio é bloqueada (desbloqueio: bloqueio método IO voltou)
  3. Tarefa tentando chamar seu método de controle síncrono em um objeto, mas o bloqueio do objeto não está disponível porque a outra tarefa tenha sido obtida, a fechadura. Esse segmento está tentando obter um monitor de sincronização (bloqueio) , mas o monitor sincronização está sendo realizada por outro segmento. Conhecimento de monitor de sincronização (bloqueio), este último será introdução mais aprofundada (levante o bloqueio: tentando obter monitor de sincronização obtida com sucesso)
  4. Chamando wait () suspende o fio , o fio está à espera de um aviso ( a notificar ou Signal ) (Desbloquear: uma notificação emitida por outros segmentos de espera)
  5. Programa chama do segmento de suspensão () método do fio é suspenso. No entanto, este método é fácil de levar a um impasse , então você deve tentar evitar o uso deste método. (Desbloquear: chamada de resdme()método de recuperação)

Aviso de rescisão fio

  • Erro de exceção ou segmento lança uma uncaught
  • O fio chamar diretamente stop () método para acabar com o fio - que facilmente levar a um impasse, geralmente não é recomendado

Outras considerações sobre o ciclo de vida

  • A declaração de rendimento (ou seja Thread.yield()): indica que o segmento tenha concluído o ciclo de vida da parte mais importante, agora é um momento oportuno para mudar para outro período de execução da tarefa de tempo. Isto é completamente opcional, que pode ocorrer ou não ocorrer .
  • Conversão entre o estado de funcionamento de prontidão e, geralmente, são não sujeito a controle de programa , mas pelas agendamento de segmento sistema de decisões.
  • A fim de testar um fio já está morto , você pode chamar o objeto segmento isAlive()método, quando o segmento está pronto, correndo, bloqueando quando três estados, o método retorna true ; quando o segmento está em Nova morte estado, o método retorna falso
  • Não tente chamar o início de um método mortos thread () para reiniciá-lo, a morte é a morte, o fio não estará disponível novamente como um fio. Irá lançar uma exceção IllegaIThreadStateException
  • declaração de sono:

processamento de linha comum

prioridade

Ele pode ser usado getPriority()e setPriority()para ler e definir a prioridade thread (prioridade no run()início do set, configurá-lo no construtor nenhum benefício porque a tarefa ainda não foi iniciado. TODO: ??? ainda para apreciar este ponto ) .

Para fazer a portabilidade prioridade segmento, quando ajustar a prioridade quando se utiliza apenas MAX_PRIORITY, NORM_PRIORITY e MIN_PRIORITY três níveis.

concessões rendimento

Usando o rendimento é programador recomendado permite que outros segmentos que utilizam CPU, mas não há nenhum mecanismo para garantir que ele seria adotado, o rendimento proposto também têm a mesma prioridade de outros tópicos pode ser executado por qualquer controle significativo ou ajustar a aplicação é não somos dependentes do rendimento.

A declaração de rendimento (ou seja Thread.yield()): indica que o segmento tenha concluído o ciclo de vida da parte mais importante, agora é um momento oportuno para mudar para outro período de execução da tarefa de tempo. Isto é completamente opcional, que pode ocorrer ou não ocorrer .

discussão de fundo

  • É um não-thread principal fundo.

  • Ele deve ser chamado antes do início rosca setDaemon(boolean on)método para defini-lo tornar-se um processo de fundo. Exemplos são como se segue:

    Thread daemon = new Thread(new Runnable() {...});
    daemon.setDaemon(true);
    daemon.start();
    
  • Qualquer segmento uma discussão de fundo criado automaticamente ajustado para uma discussão de fundo.

  • discussão de fundo terminará no final de todos os outros segmentos não-fundo, não pode executar finalmente comunicado.

Instruções para o ponto final do finally não irá:

TODO: código: remove aqui

public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 10; i++) {
        Thread daemon = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true){
                        TimeUnit.MILLISECONDS.sleep(100);
                        System.out.println(Thread.currentThread()+" "+this);
                    }
                }catch (InterruptedException e){
                    System.out.println("sleep() interruted");
                }finally {
                    System.out.println("all down");
                }
            }
        });
        daemon.setDaemon(true);
        daemon.start();
    }

    System.out.println("All started");
    TimeUnit.MILLISECONDS.sleep(175);
}
// output
All started
Thread[Thread-7,5,main] A$1@42337127
Thread[Thread-9,5,main] A$1@fb49a4f
Thread[Thread-8,5,main] A$1@47c48106
Thread[Thread-6,5,main] A$1@6fada00f
Thread[Thread-0,5,main] A$1@3cbeafaf
Thread[Thread-2,5,main] A$1@22e90474
Thread[Thread-1,5,main] A$1@3d142f7d
Thread[Thread-3,5,main] A$1@56a590e
Thread[Thread-4,5,main] A$1@1eec3130
Thread[Thread-5,5,main] A$1@2e24d89c

saída de observação pode ser encontrado, e nenhum laço da linha de fundo para imprimir, e a impressão não foi realizado finalmente em toda para baixo, para discussão de fundo sem realizar-se, finalmente, encerrar o método de execução

Este comportamento está correto, mesmo se você prometido anteriormente para baseada dar-final e não quer esse comportamento, mas a situação vai continuar assim. Quando o último fio não-fundo para terminar, discussão de fundo será "de repente" encerrado. Portanto, uma vez que a saída principal, JVM irá fechar todos os processos em segundo plano imediatamente, sem qualquer forma de reconhecimento de que você quer que apareça. Porque você não pode ser uma maneira elegante para desligar uma discussão de fundo, para que eles não são quase uma boa idéia. Não fundo Executor é geralmente uma maneira melhor, porque todos as tarefas de controle Executor pode ser desligado em simultâneo. Como você verá mais adiante neste capítulo. Neste caso, a execução será encerrado de uma forma ordenada.

juntar um fio

Se um segmento chama de t em outro segmento t.join(), um segmento dessa chamada será suspensa até que o fim da rosca alvo t foi restaurada. Você também pode t.join()adicionar um parâmetro de tempo limite quando você chama, por isso, se o segmento-alvo, no final deste período, não tinha expirado, então se juntar método sempre retorna.

Chamada para se juntar método pode ser interrompido, a prática é para chamar o método de interrupção no thread de chamada.

Capturar a exceção no segmento

Devido à natureza das características do fio, de modo que não podemos escapar de exceção fio de captura. Pode Thread.UncaughtExceptionHandlerser para o tratamento de exceção, um processador de excepções que permite a fixação em cada objecto de discussão.

Estratégia: Se você sabe que vai estar usando o mesmo código em todos os lugares manipulador de exceção, em seguida, a maneira mais fácil é definir um campo estático na classe Thread e definido como o manipulador de exceção não capturada padrão neste processador. Ele será chamado caso do manipulador de exceção não capturada do processador apenas em específico da thread inexistente. O sistema verifica a versão específica para o segmento, se não for encontrado, verifique se o grupo segmento tem sua própria proprietária uncaughtException()método, se não, em seguida, chamar defaultUncaughtExceptionHandler. Como um exemplo:

public class SettingDefaultHandler {
  public static void main(String[] args) {
    Thread.setDefaultUncaughtExceptionHandler(
      new MyUncaughtExceptionHandler());
    ExecutorService exec = Executors.newCachedThreadPool();
    exec.execute(new ExceptionThread());
  }
}

Outro processo importante

A seguir descreve o comprimento de processamento é demasiado longo, ver a Secção Esta seção tem

  1. ThreadLocal armazenamento local
  2. Fim da tarefa / thread
  3. A colaboração entre os tópicos

Tópicos Considerações

Se é thread-safe

  • variáveis estáticas thread-safe , veja as notas sob o Runnable exemplar acima descrito
  • Impressão declarações thread-safe

referência

  1. Java multi-enfiar aprendizagem (c) --- ciclo de vida rosca
  2. Capítulo recíprocas ideias de programação quarta edição Java versão chinesa

Acho que você gosta

Origin www.cnblogs.com/cheaptalk/p/12549685.html
Recomendado
Clasificación