Use wait () e notify () para obter colaboração entre thread
1. Aguarde () e notify ()/notifyAll ()
Quando o sono () e o rendimento () são chamados, o bloqueio não é liberado e a chamada wait () liberará o bloqueio. Dessa maneira, outra tarefa (Thread) pode obter o bloqueio do objeto atual, inserindo assim seu método sincronizado. Você pode retomar a execução do wait () através do notify ()/notifyAll () ou o tempo expira.
Espera (), notify () e notifyAll () só podem ser chamados no método de controle de sincronização ou no bloco de sincronização. Se esses métodos forem chamados em um método assíncrono, uma exceção ilegalMonitorStateException será lançada em tempo de execução.
2. Simule o despertar de vários threads por um único tópico
Simule a colaboração entre os threads. A aula de jogo possui 2 métodos de sincronização preparam () e go (). O início do sinalizador é usado para determinar se as necessidades de encadeamento atuais esperam (). A instância da aula de jogo inicia todas as instâncias da aula de Atele primeiro e entra no estado wait (). Após um período de tempo, altere o bit de bandeira e notifiquel () todos os threads de atele no estado de espera.
Game.java
pacote concorrência; importar java.util.collection; importar java.util.collections; importar java.util.hashset; importar java.util.iterator; importar java.util.set; classe atleta implementa executáveis {private final int id; jogo particular de jogo; public atleta (int id, jogo de jogo) {this.id = id; this.game = jogo; } public boolean é igual (objeto o) {if (! (o instância de atleta)) retornar false; Atleta atleta = (atleta) o; Return ID == Athlete.id; } public string tostring () {return "atleta <" + id + ">"; } public int hashCode () {return New Integer (id) .hashCode (); } public void run () {try {game.Prepare (this); } catch (interruptedException e) {System.out.println (this + "Quit the Game"); }}} classe pública o jogo implementa Runnable {Private Set <THELETE> PLAYERS = NOVO HASHSET <THELETE> (); private boolean start = false; public void addPlayer (atleta um) {players.add (um); } public void RemowPlayer (atleta um) {players.remove (um); } coleção pública <THELETE> getPlayers () {return collection.unmodifiableSet (jogadores); } public void preparar (atleta atleta) lança interruptedException {System.out.println (atleta + "pronto!"); sincronizado (this) {while (! start) espera (); if (start) system.out.println (atleta + "go!"); }} public sincronizado void go () {notifyAll (); } public void Ready () {iterator <THELETE> iter = getPlayers (). Iterator (); while (iter.hasnext ()) novo thread (iter.next ()). start (); } public void run () {start = false; System.out.println ("Ready ..."); System.out.println ("Ready ..."); System.out.println ("Ready ..."); preparar(); start = true; System.out.println ("Go!"); ir(); } public static void main (string [] args) {jogo game = new Game (); para (int i = 0; i <10; i ++) game.addplayer (novo atleta (i, jogo)); novo thread (jogo) .start (); }} resultado:
Pronto ... pronto ... pronto ... atleta <0> Pronto! Atleta <1> Pronto! Atleta <2> Pronto! Athlete <3> Pronto! Athlete <4> Pronto! Athlete <5> Pronto! ATHLETE <6> Pronto! Athlete <4> Athlete! vá! atleta <5> vá! atleta <4> vá! atleta <3> vá! atleta <2> vá! atleta <1> vai! atleta <0> vai!
3. Simule o processo de espera ocupado
Uma instância da classe MyObject é o observador. Quando ocorre um evento de observação, ele notificará uma instância da classe Monitor (a maneira como é alterar um sinalizador). A instância desta classe Monitor verifica constantemente se o bit de sinalizador muda esperando.
Busywaiting.java
importar java.util.concurrent.timeunit; classe myObject implementa runnable {private monitor; public myObject (monitor) {this.monitor = monitor; } public void run () {try {timeUnit.seconds.sleep (3); System.out.println ("eu vou"); monitor.GotMessage (); } catch (interruptedException e) {e.printStackTrace (); }}} Monitor de classe implementa Runnable {Private volátil boolean go = false; public void getMessage () lança interruptedException {go = true; } public void Watching () {while (go == false); System.out.println ("Ele se foi."); } public void run () {Watching (); }} classe pública Busywaiting {public static void main (string [] args) {monitor = new Monitor (); MyObject o = new MyObject (monitor); novo thread (o) .start (); novo thread (monitor) .start (); }} resultado:
Eu estou indo. Ele se foi.
4. Use wait () e notify () para reescrever o exemplo acima
O exemplo a seguir substitui o mecanismo de espera ocupado através da espera (). Quando uma mensagem de notificação for recebida, notifique o thread atual da classe Monitor.
Espera.java
pacote concurrency.wait; importar java.util.concurrent.timeUnit; classe myObject implementa Runnable {private Monitor Monitor; public myObject (monitor) {this.monitor = monitor; } Comece o tópico regularmente
Aqui estão duas maneiras de iniciar um tópico após um tempo especificado. Primeiro, é implementado através de java.util.concurrent.delayqueue; Segundo, ele é implementado através do java.util.concurrent.scheduledThreadpoolExecutor.
1. Java.util.Concurrent.Delayqueue
A classe Atraso é uma fila de bloqueio ilimitado da qual os elementos só podem ser extraídos quando o atraso expirar. Ele aceita instâncias que implementam a interface atrasada como elementos.
<< interface >> atraso.java
pacote java.util.Concurrent; importar java.util.*; interface pública atrasada estende comparável <oulded> {long getDelay (unidade de unidade timeunit);}getDelay () retorna o tempo de atraso restante associado a esse objeto, expresso em determinadas unidades de tempo. A implementação desta interface deve definir um método compareto que forneça uma classificação consistente com o método getDelay dessa interface.
A cabeça da fila de atraso é o elemento atrasado, com o tempo de armazenamento mais longo após o término do atraso. O vencimento ocorre quando o método getDelay (timeUnit.niossegunds) de um elemento retorna um valor menor ou igual a 0.
2. Filas de projeto com características de atraso de tempo
A classe toutTasker mantém uma fila de atraso <ouledTask>, onde o atraso do Trask implementa a interface atrasado e é definido por uma classe interna. Tanto as classes externas quanto as classes internas implementam a interface executável. Para classes externas, seu método de execução retira tarefas na fila em sequência de acordo com o tempo definido, e essas tarefas são instâncias de classes internas. O método de execução das classes internas define a lógica específica de cada encadeamento.
A essência desse design é definir uma lista de tarefas de thread com características de tempo, e a lista pode ter qualquer comprimento. Especifique o tempo de inicialização sempre que adicionar uma tarefa.
Touchedtasker.java
pacote com.zj.timedTask; importar java estático.util.concurrent.timeunit.seconds; importar java estático.util.concurrent.timeunit.nanoseConds; import Java.util.Collection; importar java.util.aLlections; importa.tta.util.Collection; java.util.Concurrent.Delayed; importar java.util.concurrent.executorService; importar java.util.concurrent.executores; importar java.util.Concurrent.TimeUnit; classe pública Atrasada de retardo runnable {atraso <woLQUETASTAcask> public void addtask (touchedTask e) {Queue.put (e); } public void removeTask () {Queue.poll (); } Coleção pública <AltEdTask> getAlltasks () {return collectionS.unmodifiAblecllection (fila); } public int getTaskquantity () {return fileue.size (); } public void run () {while (! } catch (interruptedException e) {System.out.println ("interrompido"); } System.out.println ("acabado toutTask"); } classe estática public estática tardia os implementos atrasados, executados {private static int contat = 0; private final int id = contador ++; PRIVADO FINAL INT Delta; gatilho final privado final; public toutTask (int deLewInseconds) {delta = deLearInseconds; trigger = system.nanotime () + nanoseconds.convert (delta, segundos); } public Long GetDelay (unidade de TimeUnit) {return Unit.Convert (Trigger - System.nanotime (), nanossegundos); } public int compareto (AGRAGEM ALENTE) {toutTask que = (touchedTask) arg; if (trigger <that.trigger) retorna -1; se (gatilho> that.trigger) retorna 1; retornar 0; } public void run () {// Execute tudo o que deseja fazer system.out.println (this); } public string tostring () {return "[" + delta + "s]" + "tarefa" + id; }} public static void main (string [] args) {rand Rand = new Random (); ExecutorService Exec = executores.newcachedthreadpool (); TheoutTasker Tasker = new AtardTasker (); for (int i = 0; i <10; i ++) tasker.addTask (novo touchedTask (Rand.NextInt (5))); EXEC.EXECUTE (Tasker); exec.shutdown (); }} resultado:
[0s] Tarefa 1 [0s] Tarefa 2 [0s] Tarefa 3 [1S] Tarefa 6 [2S] Tarefa 5 [3S] Tarefa 8 [4S] Tarefa 0 [4S] Tarefa 4 [4S] Tarefa 7 [4S] Tarefa 9FinishedDaLayedTaskSask
3
Esta classe pode ser programada para executar tarefas (threads) após um determinado atraso ou para executar tarefas regularmente (repetir). No construtor, você precisa saber o tamanho do pool de threads. O principal método é:
[1] Cronograma
Public ScheduledFuture <?> Schedule (comando executável, atraso longo, unidade de unidade de tempo)
Cria e executa uma operação única ativada após um determinado atraso.
Designado por:
- Agenda na interface ScheduledExecutorService;
parâmetro:
-Command - a tarefa a ser executada;
-Delay - a hora de atrasar a execução a partir de agora;
-unidade - a unidade de tempo dos parâmetros de atraso;
retornar:
- Indica o Future Schedulled Future que suspende a tarefa e seu método get () retornará nulo após a conclusão.
[2] ScheduleatFixedrate
Public ScheduledFuture <?> scheduleatfixedrate (
Runnable Command, Long InitialDelay, Longo Período, Unidade Timeunit)
Crie e execute uma operação periódica que seja ativada pela primeira vez após um determinado atraso inicial, com operações subsequentes tendo um determinado período; isto é, ele começará após o InitialDelay, depois após o período do InitialDelay +, depois do período inicial do Saly + 2 * e assim por diante. Se alguma execução de uma tarefa encontrar uma exceção, a execução subsequente será cancelada. Caso contrário, a tarefa só pode ser encerrada executando o método de cancelamento ou rescisão do programa. Se alguma das execuções desta tarefa levar mais tempo que seu ciclo, a execução subsequente será adiada, mas não simultaneamente.
Designado por:
- ScheduleAtFixedrate na interface ScheduleDexecutorService;
parâmetro:
-Command - a tarefa a ser executada;
-InitialDelay - o tempo de atraso para a primeira execução;
-Period - o período entre execuções contínuas;
-unidade - a unidade de tempo dos parâmetros iniciais e periódicos;
retornar:
- Indica que o FUTURO AGENDELED da tarefa suspensa é concluído e seu método get () lançará uma exceção após o cancelamento.
4. Executores de threads de design com características de atraso de tempo
A classe ScheduleTasked associa um ScheduledThreadPoolExCutor, que pode especificar o tamanho do pool de threads. Conheça o tempo de encadeamento e atraso através do método de cronograma e feche o pool de threads através do método de desligamento. A lógica de tarefas específicas (threads) tem certa flexibilidade (em comparação com o design anterior, o design anterior deve definir a lógica do thread com antecedência, mas o design lógico específico do Thread pode ser modificado por herança ou decoração).
ScheduleTasker.java
pacote com.zj.timedTask; importar java.util.concurrent.scheduledThreadpoolExecutor; importar java.util.concurrent.timeunit; public class ScheduleTasker {private int CorePoolSize = 10; ScheduledThreadpoolExecutor Scheduler; public ScheduleTasker () {Scheduler = new ScheduledThreadPoolExector (CorePoolSize); } public ScheduleTasker (int Quantity) {CorePoolSize = Quantity; Scheduler = new ScheduledThreadpoolExector (CorePoolSize); } cronograma de void public (Evento Runnable, Longo Atraso) {Scheduler.Schedule (Evento, Atraso, TimeUnit.Seconds); } public void Shutdown () {Scheduler.shutdown (); } public static void main (string [] args) {scheduleTasker tasker = new ScheduleTasker (); Tasker.Schedule (new Runnable () {public void run () {System.out.println ("[1S] Task 1");}}, 1); Tasker.Schedule (new Runnable () {public void run () {System.out.println ("[2S] Task 2");}}, 2); Tasker.Schedule (new Runnable () {public void run () {System.out.println ("[4S] Task 3");}}, 4); Tasker.Schedule (new Runnable () {public void run () {public void run () {System.out.println ("[10s] Task 4");}}, 10); tasker.shutdown (); }} resultado:
[1S] Tarefa 1 [2S] Tarefa 2 [4S] Tarefa 3 [10s] Tarefa 4 public void run () {try {timeUnit.seconds.sleep (3); System.out.println ("eu vou"); monitor.GotMessage (); } catch (interruptedException e) {e.printStackTrace (); }}} classe Monitor implementa Runnable {private volátil boolean go = false; public sincronizado void getMessage () lança interruptedException {go = true; notificar (); } public sincronizado void Watching () lança interruptedException {while (go == false) wait (); System.out.println ("Ele se foi."); } public void run () {try {Watching (); } catch (interruptedException e) {e.printStackTrace (); }}} classe pública espera {public static void main (string [] args) {monitor monitor = new Monitor (); MyObject o = new MyObject (monitor); novo thread (o) .start (); novo thread (monitor) .start (); }} resultado:
Eu estou indo. Ele se foi.