JAVA learning - multithreading

Multithreading

Thread

  • Custom Thread class inherits Thread class
  • Rewrite the run() method and write the thread execution body
  • Create a thread object and call the start() method to start the thread

Note: if you call the run() method, there is only one execution path for the main thread, but if you call the start() method, there are multiple execution paths, and the main thread and sub thread execute in parallel and alternately

package com.myThread.demo01;

public class Demo01 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        for (int i = 0; i < 10000; i++) {
            System.out.println("I'm the main thread--"+i);
        }
    }
}
///////////////////////////
package com.myThread.demo01;

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("I'm a child thread--"+i);
        }
    }
}

**The execution of the thread is determined by the CPU**

Network picture download

You need to use the commons io package, download the binary file from Baidu, and then copy and paste it into idea to create a new lib package

package com.myThread.demo02;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class Demo01 {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread("https://img2022.cnblogs.com/blog/1755845/202202/1755845-20220206182923194-2117509516.png","4.jpg");
        MyThread myThread2 = new MyThread("https://img2022.cnblogs.com/blog/1755845/202203/1755845-20220303112203654-338817152.png","5.jpg");
        MyThread myThread3 = new MyThread("https://img2022.cnblogs.com/blog/1755845/202202/1755845-20220223223043340-1183125272.png","6.jpg");
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}
//Sub thread write and download to realize multi-threaded download of resources
class MyThread extends Thread{
    private String myUrl = null;
    private String myname = null;

    public MyThread(String url,String name) {
        this.myname = name;
        this.myUrl = url;
    }

    @Override
    public void run() {
        WebDownload webDownload = new WebDownload();
        webDownload.download(myUrl,myname);
        System.out.println("Download it"+myname);
    }
}
//Downloader
class WebDownload{
    public void download(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Exception in downloader method!");
        } finally {
        }

    }
}

It is proved once again that threads are allocated by CUP and cannot be interfered by human beings

Runnable interface

Thread creation mode 2: implement the runnable interface, rewrite the run method, and the execution thread needs to throw in the object

package com.myThread.demo03;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("I am reading a book--"+i);
        }
    }
}
////////////////////////
package com.myThread.demo03;

public class Demo01 {
    public static void main(String[] args) {
        new Thread(new MyRunnable()).start();//Here, create a new Thread and throw in the object that implements the runnable interface
        for (int i = 0; i < 2000; i++) {
            System.out.println("I am playing mobile phone.--"+i);
        }


    }
}

It is better to use runnable interface to realize multithreading, avoid the limitation of single inheritance, be flexible and convenient, and make it convenient for the same object to be used by multiple threads

Understanding concurrency problems

package com.myThread.demo04;

public class MyTicket implements Runnable{
    private int ticketNums = 1;

    @Override
    public void run() {
        while (true){
            if (ticketNums>=20){
                break;
            }
            try {
                Thread.sleep(200);//Analog delay
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
            }
            //Thread.currentThread().getName() can get the name of the current thread, where the three threads use the same object 
            System.out.println(Thread.currentThread().getName()+"--Got the third"+ticketNums+++"Tickets!");
        }
    }
}
////////////////////
package com.myThread.demo04;

public class Demo01 {
    public static void main(String[] args) {
        MyTicket ticket = new MyTicket();//Just one new object
        //Three threads use the same object
        new Thread(ticket,"Zhang San").start();
        new Thread(ticket,"Li Si").start();
        new Thread(ticket,"Wang Wu").start();

    }
}

Operation results:

Li Si and Wang Wu both grabbed the second ticket, indicating that the thread is unsafe and there is a data disorder. This is the problem of thread concurrency.

Tortoise and rabbit race

Asked to track 100, the rabbit and the tortoise ran together, but the rabbit had to sleep and the tortoise won

package com.myThread.demo05;

public class Race implements Runnable{
    private int steps = 1;
    private static String winner;
    @Override
    public void run() {
        while (true){

            if (Thread.currentThread().getName().equals("rabbit") && steps%10 == 0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                }
            }

            if (theWinner(steps)){//Small details, the judgment should be put after the rabbit is dormant, which can avoid the rabbit from running another step after accepting the competition
                break;
            }

            System.out.println(Thread.currentThread().getName()+"--It's gone"+steps+++"step");


        }
    }
    public boolean theWinner(int steps){
        if (winner != null){
            return true;//This sentence must be written, or the rabbit or tortoise will not stop after running another thread!!
        }
        else if (steps>=100 && winner == null){
            winner = Thread.currentThread().getName();
            System.out.println(winner+"Victory!");
            return true;
        }
        return false;

    }
}
////////////////////////////
package com.myThread.demo05;

public class Demo01 {
    public static void main(String[] args) {
        Race race = new Race();
        new Thread(race,"tortoise").start();
        new Thread(race,"rabbit").start();
    }
}

Callable interface

I don't quite understand. Come back later!

Static proxy

The real object and the proxy object implement the same interface, and the proxy object should proxy the real object. The real object is passed to the proxy object through the constructor. The proxy object can not only complete the method of the real object, but also do many things that the real object does not do. The real object only needs to focus on its own things.

Lambda expression

Lambda can simplify the code, but note:

  • The interface must be functional, that is, there can only be one method with implementation
  • If there is only one line of code in the method, it can be simplified not to write curly braces. If there are multiple lines, it must be wrapped with code blocks, that is, curly braces
  • The method to be implemented of the interface contains parameters. The parameter type can be removed, and the parameter type can also be removed for multiple parameters. If you want to remove them, you must add parentheses (if there is only one parameter, the parentheses can also be removed)
  • The format is interface name = (parameter) - > {code};
package com.myThread.demo06;

public class Demo01 {
    public static void main(String[] args) {
        Marry marry = null;
        marry = ()-> System.out.println("lalla");
        marry.makeMarry();
    }
}
interface Marry{
    void makeMarry();
}

Thread stop

When the thread stops, it uses a flag flag bit in the while loop to control it

.sleep

Thread sleep

Use sleep as a timer to refresh the time every second

package com.myThread.demo07;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Demo01 {
    public static void main(String[] args) {
        Runnable runnable = null;
        runnable = ()->{
            while (true){
                LocalDateTime localDateTime = LocalDateTime.now();//Get time
                DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");//Adjust format
                System.out.println(dateTimeFormatter.format(localDateTime));//Output time in format
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                }

            }
        };
        new Thread(runnable).start();
    }
}

.yield

Thread comity

  • Comity thread: pause the currently executing thread without blocking it
  • Change the thread from running state to ready state
  • Let the cpu reschedule, comity is not necessarily successful! Look at your mood

.join

Merge threads and execute other threads after the execution of this thread is completed. Other threads are blocked

It can be understood as jumping in line

package com.myThread.demo08;

public class Demo08 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("I am vip--"+i);
        }
    }

    public static void main(String[] args) {
        Demo08 demo08 = new Demo08();
        Thread thread = new Thread(demo08);
        thread.start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("I'm the main thread--"+i);
            if (i == 1000){
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                }
            }
        }

    }
}

From the top, let the thread jump the queue. When the main thread is 1000, it will jump the queue, but the main thread will run before 1000. Fully obey the cpu scheduling, but once the main thread reaches 1000, it will forcibly jump the queue and start the main thread after the thread runs

Observation thread

Thread.State state = thread.getState();
System.out.println(state);

thread priority

**set priority() get priority() **

Daemon thread

set daemon()

The daemon thread will stop when the user thread ends and the virtual machine stops. The virtual machine does not wait for the daemon thread to run.

package com.myThread.demo09;

public class Demo01 {
    public static void main(String[] args) {
        You you = new You();
        God god = new God();
        new Thread(you).start();
        Thread thread = new Thread(god);
        thread.setDaemon(true);
        thread.start();
    }
}

class You implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i < 36500; i++) {
            System.out.println("The living third--"+i+"day");
        }
        System.out.println("=====goodbye,world!=====");
    }
}
class God implements Runnable{

    @Override
    public void run() {
        while (true){
            System.out.println("God looks at you");
        }
    }
}

Although the above god thread uses a while(true) loop, the program will also stop when the user thread stops and then the virtual machine stops. (it takes a little time for the virtual machine to stop)

Unsafe problem

The unsafe problem of bank withdrawal. The code is a little unsatisfactory. Make do with it. There is indeed thread insecurity

package com.unsafeDemo.demo01;
//The thread of bank withdrawal is not safe
public class Demo01 {
    public static void main(String[] args) {
        Account account = new Account(100,"shebang");
        Bank bank = new Bank(account,50,"Xiao Ming");
        Bank bank1 = new Bank(account,70,"Xiao Hong");
        new Thread(bank).start();
        new Thread(bank1).start();
    }
}
class Account {
    int money;
    String name;
    public Account(int money, String name){
        this.money = money;
        this.name = name;

    }
}

class Bank implements Runnable{
    Account account ;
    private int drawingMoney;
    private String name;
    public Bank(Account account, int drawingMoney, String name){

       this.drawingMoney = drawingMoney;
       this.account = account;
       this.name = name;
    }
    public void drawingMoney(){
        account.money = account.money - drawingMoney;
        System.out.println(this.name+"Yes"+drawingMoney);
        System.out.println("The balance is"+account.money);
    }

    @Override
    public void run() {
        if (drawingMoney > account.money){
            System.out.println("No money, take chicken feathers");
            return;
        }
        try {
            Thread.sleep(100);//Using delay amplification problem
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        drawingMoney();


    }
}

Synchronization block

synchronized (Obj){}

Obj can be any object. Fill in the object that needs to be locked, that is, the object with change, and then put the code of the change process in this synchronization block.

Lock

The lock that can display words, generally using ReentrantLock class (reentrant lock)

Review without lock first:

package com.unsafeDemo.demo02;

public class Demo02 {
    public static void main(String[] args) {
        BuyTicks ticks = new BuyTicks();
        Thread t1 = new Thread(ticks,"I");
        Thread t2 = new Thread(ticks,"you");
        Thread t3 = new Thread(ticks,"he");
        t1.start();
        t2.start();
        t3.start();
    }
}
class BuyTicks implements Runnable{
    private int ticks = 10;
    boolean flag = true;

    @Override
    public void run() {
        while(flag) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (ticks > 0) {
                System.out.println(Thread.currentThread().getName() + "Got the third" + ticks-- + "ticket");
            }else {
                flag = false;
            }
        }
    }
}

Locking code:

package com.unsafeDemo.demo02;

import java.util.concurrent.locks.ReentrantLock;

public class Demo02 {
    public static void main(String[] args) {
        BuyTicks ticks = new BuyTicks();
        Thread t1 = new Thread(ticks,"I");
        Thread t2 = new Thread(ticks,"you");
        Thread t3 = new Thread(ticks,"he");
        t1.start();
        t2.start();
        t3.start();
    }
}
class BuyTicks implements Runnable{
    private int ticks = 10;
    boolean flag = true;
    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {

        try {
            lock.lock();
            while(flag) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticks > 0) {
                    System.out.println(Thread.currentThread().getName() + "Got the third" + ticks-- + "ticket");
                }else {
                    flag = false;
                }
            }
        } finally {
            lock.unlock();

        }
    }
}

Note that the modifier private final is added to the new ReentrantLock. I don't understand, but draw the ladle according to the gourd, and then lock and unlock it. Put it in catch finally. I don't understand. Continue to draw the ladle according to the gourd.

bounded-buffer problem

wait() notifyAll() can only be written in synchronized

package com.myPC.demo03;

public class Demo03 {
    public static void main(String[] args) {
        MyContainer myContainer = new MyContainer();
        new Productor(myContainer).start();
        new Consumer(myContainer).start();

    }
}
class Productor extends Thread{
    MyContainer myContainer;

    public Productor(MyContainer myContainer) {
        this.myContainer = myContainer;
    }

    @Override
    public void run() {
        for (int i = 1; i < 100; i++) {
            myContainer.push(new Chicken(i));
            System.out.println("Produced the second"+i+"Chicken");

        }

    }
}
class Consumer extends Thread{
    MyContainer myContainer;

    public Consumer(MyContainer myContainer) {
        this.myContainer = myContainer;
    }

    @Override
    public void run() {
        for (int i = 1; i < 100; i++) {
            System.out.println("Consumed the second"+myContainer.del().id+"Chicken");
        }


    }

}
class Chicken{
    int id;

    public Chicken(int id) {
        this.id = id;
    }
}
class  MyContainer{
    Chicken[] chickens = new Chicken[10];
    int count = 0;
    public synchronized void push(Chicken chicken){
        while (count >= chickens.length){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        chickens[count] = chicken;
        count++;
        notifyAll();//Wake up all threads, including consumption threads that stop when there is no chicken

    }

    public synchronized Chicken del(){
        if (count <= 0){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;
        Chicken chicken = chickens[count];
        notifyAll();//Wake up all threads, including production threads that are stopped when the chicken is full
        return chicken;
    }


}

Thoughts on wait() and notifyAll()

package com.myPC.demo04;

import java.util.concurrent.locks.ReentrantLock;

public class Demo04 {
    public static void main(String[] args) {
        abc abc = new abc();
        new Thread(abc,"a").start();
        new Thread(abc,"b").start();
    }

}
class abc implements Runnable{
    int count = 1;
    @Override
    public synchronized void run() {
        for (int i = 0; i < 19; i++) {


            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (Thread.currentThread().getName().equals("a") && count%5==0  ){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("a Wake up!");
                }
            while (Thread.currentThread().getName().equals("b") && count%4==0 ){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("b Wake up!");
            }
                System.out.println(Thread.currentThread().getName()+"--Got it"+count);
                count++;
                notifyAll();
            
        }
    }

}

This code is to ask ab to get the number. At first, a is assigned by the cpu to get it, but when a enters the while loop and meets the wait, a stops. At this time, the cpu will directly ask b to continue to get the number and wake a up through notifyAll. Whether a will get the number depends on the cpu scheduling. However, once b enters the while loop and meets the wait, It will make a continue to go down from the wait that a stops. As long as a is awakened from sleep and then scheduled by the cpu, it will continue to execute from the wait.

Signal lamp method

Using a flag flag bit to solve the problem of producers and consumers

Thread pool

ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor

Executors: tool class, factory class of thread pool, which is used to create and return different types of thread pools

package com.myPC.demo05;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo05 {
    public static void main(String[] args) {
        //Create a thread pool service
        ExecutorService service = Executors.newFixedThreadPool(3);//The meaning of the parameter is the size of the thread pool
        //implement
        service.execute(new MyPool());
        service.execute(new MyPool());
        service.execute(new MyPool());
        //Close thread pool
        service.shutdown();

    }
}
class MyPool implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

The thread pool is similar to the Runnable interface

Added by jcstanley on Mon, 07 Mar 2022 12:55:15 +0200