Problemas em entender Threads

Bom dia pessoal do Fórum, estou fazendo um treinamento em Java, e um dos temas é Thread, bom , acredito ser comum encontrar dificuldades nesse tema, pois apesar de importante, não são conceitos tão simples ao meu ver, talvez fica mais claro daqui pra frente.

Bom, vou descrever aqui as impressões que eu tive e colocar as dúvidas conforme o parte do assunto que eu estiver tratando.

A principio, para se criar Threads, existem duas maneiras, uma implementando a interface Runnable, e outra extendendo a propria classe Thread, me pareceu ser mais vantajoso implementar a interface Runnable, pois da mais flexibilidade a classe, e depois, para acessar o Metodos da classe thread, posso criar uma outra classe, passando como parametro minha classe criada implementado a Runnable.

O método run(), é o local onde se tem a ação do que o thread ira fazer, e deve haver uma laço de repetição, um continuo se quiser que a thread sempre efetue determinada tarefa, ou determinar o fim do laço em determinada condição, que ao se efetuar, se encerra o ciclo da thread.
Notei que o método sleep da classe thread, é praticamente sempre usado no método run(), bom pelo que notei, ao usar o método sleep, ao executar o laço uma vez, a thread entre em espera no tempo determinado, liberando a CPU de seu processamento, e esperando para executar novamente, bom, se eu colocar um looping infinito, um while(true), e nao definir um sleep, pelo que testei, essa thread ficara executando o tempo todo que o ssistema estiver ativo, sem dar espaço para outras threads, certo?

fiz um teste, o seguinte :

tenho duas classes que implementam a runnable, e seus respetivos métodos run():


public class Thread1 implements Runnable {

public void run(){
  try{
     int i = 0;
      while (true) {
        System.out.println("THREAD 1");
        i++;

        if (i == 10){
          Thread.sleep(2000);
           i = 0;

        }
       


       }

  }
  catch (InterruptedException e){
    System.err.println("Erro!");
   }
 
}

}

Public class Thread2 implements Runnable {

public void run(){
  try{
     int i = 0;
      while (true) {
        System.out.println("THREAD 2");
        i++;

        if (i == 10){
          Thread.sleep(2000);
           i = 0;
        }


       }

  }
  catch (InterruptedException e){
    System.err.println("Erro!");
   }
 

}

}

E na principal os chamei:


import.threadsteste.*;

public class Principal{
       public static void main(String args[]){
          Thread1 t1 = new Thread1();
          Thread2 t2 = new Thread2();
          Thread thread1 = new Thread(t1);
          Thread thread2 = new Thread(t2);

          thread1.start();
          thread2.start();

 }

}

Dai, ok, ele executado por 10x, pausa, 2 segundos no caso, e nesse tempo, o outro Thread começar executar, e assim vai.

Bom, eu usei somente o metodo start() da classe Thread, e o sleep, mas tem varios outros como todos sabem, o wait, yeald, interrupt, join, notify, notifyAll…e eu não entendo muito bem para que eles servem.

O wait(), notify() e notifyAll(), nao entendi em que momentos eles devem ser chaamados, nao fiz este teste no programa, mas vou descrever a situação para analiseram se seria nessas condições:

Eu tenho determinado Thread que executa a cada 3 horas e envia emails para número x de pessoas, porem tenho uma verificação, se o dia for sabado e domingo, eu daria um wait nele, corresponde ao periodo do fds, mas se mesmo sendo sabado, for sabado que cai no dia 31, dai eu dou um notify nele, pq nesse fdp, ele teria que trabalhar normalmente, nao entendi mt bem a desses metodos…

o yeald(), ele para a execução da Thread pelo que li, bom entao se eu , pegando por exemplo minha thread1, ele executa 10x, dai ela para por 2segundos, se eu colocar um yeald quando ela tiver executado 5x, ela força uma parada, que seria a morte da thread?

O join, como eu usaria, pra que?

o interrupt, a thread não seria interrompida, é a mesma função de syncronized pode se dizer?

Talvez quando alguem responda eu nem tenha mais essas duvidas, porque enquanto espero as respostas, vou pesquisar mais sobre isso também, já li o artigo aqui do forum sobre Threads mesmo assim, essas coisa em questão ainda me confundem, vou reler ele também, pois tenho qeu me parofundar um pouco mais nesse assunto e ver a parte de syncronized e pool de threads.

Peço desculpas, por perguntas que tenho certeza que para alguns será muito infantis, mas são minhas duvidas no momento :?

Obrigado a todos!

Cria uma classe implementad Runnable.

class RunnableTest implements Runnable{

public void run(){…};

}

ai faz assim em outra classe:

//Cria um objeto Runnable passando como construtor uma nova classe que você implementou Runnable, feita anteriormente:
Runnable run = new RunnableTest();//o construtor vai ser a classe que você implementou o runnable, sendo no caso aqui a
//RunnableTest

Após isso cria normalmente o Thread passando por parâmetros o objeto Runnable (run) criado antes.
Thread thread1 = new Thread(run);//aqui você cria uma thread, sendo que nos parâmetros do método construtor
//você passa o Runnable criado anteriormente

Calma! Um tópico por vez:

:arrow: Sleep vai fazer a thread interromper por um determinado período. Não precisa necessariamente ser no método run() de Runnable (é bastante comum em animações, por exemplo);
:arrow: wait() e notify() são usados em casos em que a thread deve aguardar por um tempo indefinido. Por exemplo, quando uma determinada condição é alcançada, uma thread recebe notificação para continuar. (Na verdade, esses métodos são invocados em cima de objetos, que são os recursos que estão aguardando “permissão” para continuar). Um exemplo clássico de uso desses são algoritmos produtor/consumidor, onde o consumidor deve aguardar até que haja recursos em um buffer e o produtor deve aguardar até ter espaço suficiente para colocar um recurso nesse buffer. Pesquise no google por esses algoritmos;
:arrow: yield() vai abrir espaço para que outra thread execute. Se isso vai acontecer de fato ou não, é outra história, porque depende de uma série de fatores. Encare isso como uma “dica” para a VM, não como uma regra;
:arrow: join() é usado para reunir threads (como o próprio nome já diz). Por exemplo, se você tem um problema e parte ele em vários pedaços, você pode usar join() depois para aguardar o final da execução das threads que você usou e reunir os dados processados por elas.

Enfim, espero ter dado uma luz. Tenho certeza que você tem mais dúvidas - pergunte assim, em tópicos, que fica mais fácil esclarecê-las, OK?

[]'s