Multithreading

Keywords: Java thread

1. Three methods of creating threads

  1. Inherit Thread class [key]
  • Inherit the Thread class, override the run() method, and call start to start the Thread
  • Not recommended: avoid the limitation of OOP single inheritance
//Method 1 of creating a Thread: inherit the Thread class, rewrite the run() method, and call start to start the Thread
public class Thread_one extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("Thread_one......");
        }
    }
   
    public static void main(String[] args) {
        //Create a thread object
        Thread_one thread = new Thread_one();
        //Calling the strat() method calls the thread
        thread.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main......");
        }
    }
}
  1. Implementation of Runnable interface [ key ]
  • Implement the runnable interface and rewrite the run method. The execution thread needs to drop into the runnable interface implementation class and call the start method
  • Recommended: it avoids the limitation of single inheritance, is flexible and convenient, and is convenient for the same object to be used by multiple threads
//The second way to create a thread: implement the runnable interface and rewrite the run method. The execution thread needs to throw in the runnable interface implementation class and call the start method
public class Thread_two implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("Thread.......");
        }
    }
    
    public static void main(String[] args) {
        Thread_two thread_runnable = new Thread_two();
        Thread thread = new Thread(thread_runnable);
        thread.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main......");
        }
    }
}

  1. Implement Callable interface [understand]
  • Implement the call method in the Callalbe interface. Create an execution service, submit execution, obtain results, and close the service.
//The third way to create a thread is to implement the call method in the callalbe < T > interface. Create an execution service, submit execution, obtain results, and close the service.
public class Thread_three implements Callable<Boolean>{

    private String name;
    
    public Thread_three(String name) {
        this.name = name;
    }

    @Override
    public Boolean call() throws Exception {
        for (int i = 0; i < 20; i++) {
            System.out.println(this.name +"Yes...");
        }
        return true;
    }
    
    public static void main(String[] args) {
        Thread_three t1 = new Thread_three("t1");
        Thread_three t2 = new Thread_three("t2");
        Thread_three t3 = new Thread_three("t3");

        //Create execution service
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //Submit for execution
        Future<Boolean> r1 =  ser.submit(t1);
        Future<Boolean> r2 =  ser.submit(t2);
        Future<Boolean> r3 =  ser.submit(t3);
        //Get results
        try {
            boolean rs1 = r1.get();
            boolean rs2 = r2.get();
            boolean rs3 = r3.get();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //Shut down service
        ser.shutdown();
    }
}

2. Thread method

  1. Thread five states: creation state, ready state, running state, blocking state and death state
  1. Thread method
methodexplain
setPriority(int newPriority)Change the priority of a thread
static void sleep(long millis)Hibernates the currently executing thread for the specified number of milliseconds
void join()Wait for the thread to terminate
static void yieldPauses the currently executing thread object and executes other threads
void interruptInterrupt the thread. Don't do it this way
boolean isAliveTest whether the thread is active
  1. Thread stop
/**
 * Thread stop
 *  1. It is recommended that the thread stop normally -- > utilization times, and dead loop is not recommended
 *  2. It is recommended to use flag bit -- > to set a flag bit
 *  3. Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK
 */
public class Thread_stop implements Runnable{
  //Set a flag bit
  private boolean flag = true;
  
  @Override
  public void run() {
    int i = 0;
    while(flag) {
      System.out.println("run ---> thread" + i++);
    }
  }

  public void stop() {
    this.flag = false;
  }

  public static void main(String[] args) {
    Thread_stop stop = new Thread_stop();
    for (int i = 0; i < 1000; i++) {
      if(i == 900) {
        stop.stop();
        System.out.println("The thread stopped......");
      }
    }
  }
}

3. Daemon thread

  • The virtual machine must ensure that the user thread has completed execution
  • The virtual machine does not have to wait for the daemon thread to complete execution, such as garbage collection, memory monitoring, etc
Thread thread = new Thread()
thread.setDaemon(true) //Open daemon thread

4. Thread synchronization

  • Thread synchronization: multiple threads operate on the same resource.
  • Thread synchronization is actually a waiting mechanism. Multiple threads that need to access this object at the same time enter the waiting pool of this object to form a queue, wait for the previous thread to use it, and then use it again for the next thread.
  • Locking mechanism synchronized

Synchronization method and synchronization code block

public class UnsafeBuyTicket {
  public static void main(String[] args) {
    BuyTicket station = new BuyTicket();
    new Thread(station, "a").start();
    new Thread(station, "b").start();
    new Thread(station, "c").start();
  }
}

class BuyTicket implements Runnable{
  //ticket
  private int ticketNums = 10;
  boolean flag = true;

  @Override
  public void run() {
    //Buy a ticket
    while(flag) {
      try {
        buy();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  //Synchronized: the synchronized method locks this
  private synchronized void buy() throws InterruptedException{
    //Judge whether there are tickets
    if(ticketNums <= 0) {
      flag = false;
      return;
    }

    //Analog delay
    Thread.sleep(100);

    //Buy a ticket
    System.out.println(Thread.currentThread().getName() + "Get" + ticketNums--);
  }

  //Synchronized: synchronized code blocks. The lock is the amount of change
  private void buy_() throws InterruptedException{
    synchronized(ticketNums) {
      //Judge whether there are tickets
      if(ticketNums <= 0) {
        flag = false;
        return;
      }

      //Analog delay
      Thread.sleep(100);

      //Buy a ticket
      System.out.println(Thread.currentThread().getName() + "Get" + ticketNums--);
    }
  }
}

Locking mechanism

import java.util.concurrent.locks.ReentrantLock;

public class Lock {
  public static void main(String[] args) {
    testLock lock = new testLock();
    new Thread(lock).start();
    new Thread(lock).start();
    new Thread(lock).start();
  }
}

class testLock implements Runnable {
  int ticketNums = 10;

  //Define lock lock
  private final ReentrantLock lock = new ReentrantLock();

  @Override
  public void run() {
    while(true) {      
      try {
        //Lock
        lock.lock();
        if(ticketNums > 0) {
          try {
            Thread.sleep(1000);
            System.out.println(ticketNums--);
          } catch (Exception e) {
            e.printStackTrace();
          }
        }else {
          break;
        }
      }finally{
        //Unlock
        lock.unlock();
      }
      
    }
  }
}

Priority of locks: lock mechanism > sync code block > sync method

5. Thread communication

  1. Several methods of thread communication
Method nameeffect
wait()It means that the thread has been waiting and knows that other threads notify it. Unlike sleep, it will release the lock
wait(long timeout)Specifies the number of milliseconds to wait
notify()Wake up a waiting thread
notifyAll()Wake up all threads calling the wait() method on the same object, and the threads with high priority are scheduled first
  1. Solutions to producer consumer problems
  • Pipe process method: the producer puts the produced data into the buffer, and the consumer takes out the data from the buffer
public class Pc {
  public static void main(String[] args) {
    SynContainer container = new SynContainer();
    new Productor(container).start();
    new Consumer(container).start();
  }
}

//producer
class Productor extends Thread {
  SynContainer container;
  public Productor(SynContainer container) {
    this.container = container;
  }

  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      System.out.println("Produced" + i + "Chicken");
      container.push(new Chicken(i));
    }
  }
}

//consumer
class Consumer extends Thread {
  SynContainer container;
  public Consumer(SynContainer container) {
    this.container = container;
  }

  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      System.out.println("Consumption-->" + container.pop().id + "Chicken");
    }
  }
}

//product
class Chicken {
  int id;//Product number
  public Chicken(int id) {
    this.id = id;
  }
}

//buffer
class SynContainer {
  Chicken[] chickens = new Chicken[10];
  int count = 0;
  //The producer puts in the product
  public synchronized void push(Chicken chicken) {
    //If the container is full, it needs to wait for consumers to consume
    if(count == chickens.length) {
      //Inform consumers of consumption. Production waiting
      try {
        this.wait();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    //If it is not full, we need to throw in the product
    chickens[count] = chicken;
    count++;

    //Consumers can be informed of consumption
    this.notifyAll();
  }

  //Consumer products
  public synchronized Chicken pop() {
    //Judge whether it can be consumed
    if(count == 0) {
      //Wait for producers to generate, consumers to wait
      try {
        this.wait();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    //If you can consume
    count--;
    Chicken chicken = chickens[count];

    //When finished, inform the producer to produce
    this.notifyAll();
    return chicken;
  }
}
  • Signal lamp method
public class Pc2 {
  public static void main(String[] args) {
    TV tv = new TV();
    new Player(tv).start();
    new Watcher(tv).start();
  }
}

//Producer -- > actor
class Player extends Thread {
  TV tv;
  public Player(TV tv) {
    this.tv = tv;
  }

  @Override
  public void run() {
    for (int i = 0; i < 20; i++) {
      if(i % 2 == 0) {
        this.tv.play("Central one");
      }else {
        this.tv.play("Central five sets");
      }
    }
  }
}

//Consumer -- > audience
class Watcher extends Thread {
  TV tv;
  public Watcher(TV tv) {
    this.tv = tv;
  }

  @Override
  public void run() {
    for (int i = 0; i < 20; i++) {
      tv.watch();
    }
  }
}

//Products -- > Programs
class TV {
  //The audience waited while the actors performed
  //The audience watched and the actors waited
  String voice; //A performance
  boolean flag = true;

  //perform
  public synchronized void play(String voice) {
    if(!flag) {
      try {
        this.wait();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    System.out.println("The actors performed:" + voice);
    //Inform the audience to watch
    this.notifyAll();
    this.voice = voice;
    this.flag = !this.flag;
  }

  //watch
  public synchronized void watch() {
    if(flag) {
      try {
        this.wait();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    System.out.println("The audience watched:" + voice);
    //Notice performance
    this.flag = !this.flag;
  }
}

6. Thread pool

  • Create multiple threads in advance, put them into the thread pool, obtain them directly when using them, and put them back into the pool after use. It can avoid frequent creation, destruction and reuse.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Pool {
  public static void main(String[] args) {
    //1. Create thread pool
    ExecutorService service = Executors.newFixedThreadPool(10);
    
    //2. Using threads
    service.execute(new MyThread());
    service.execute(new MyThread());
    service.execute(new MyThread());
    service.execute(new MyThread());

    //3. Close the connection
    service.shutdown();
  }
}

class MyThread implements Runnable {
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      System.out.println(Thread.currentThread().getName() + i);
    }
  }
}

Posted by pixeltrace on Mon, 22 Nov 2021 14:29:21 -0800