Multithreaded notes

Multithreading

Create thread

There are three ways to create threads

  1. Inherit the Thread class and override the run method
  2. Implement Runnable interface
  3. Implement Callable interface

Inherit Thread class

Inherit the Thread class and override the run method

package Thread;

public class MyThread extends Thread{
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            System.out.println("Child thread..........."+i);
        }
    }
}
package Thread;

public class TestThread {
    public static void main(String[] args) {
        //Create thread object
        MyThread myThread = new MyThread();
        //2 start the thread. Using the run method is equivalent to calling the run method by the object. It is a single thread
        myThread.start();
        //Main thread execution
        for (int i = 0;i < 50;i++){
            System.out.println("Main thread============"+i);
        }
    }
}

Get thread name

Get thread ID and thread name

1. invoke this. in the subclass of Thread Getid () or this getName()

2. Use thread currentThread(). Getid () and thread currentThread (). getName ()

3. Modify thread name

Call the setName() method of the thread object.

Use the constructor of thread subclass to assign values.

    public void run() {
        for(int i = 0;i<100;i++){
            //this.getId get thread Id
            //this.getName get thread name
            //The first method needs to inherit the Thread class
            System.out.println("thread  id: "+this.getId()+"Thread name"+getName()+"Child thread..........."+i);
        }
            //The second method is thread Currentthread() gets the current thread
            
            System.out.println("thread  id: "+Thread.currentThread()+"Thread Name:"+Thread.currentThread().getName());        

Get and modify thread name

Modify thread name

Call the setName() method of the thread object.

Use the constructor of thread subclass to assign values.

//Modify thread name
MyThread myThread = new MyThread();
myThread.setName("My child thread 1");
myThread.start();

MyThread myThread2 = new MyThread();
myThread2.setName("My child thread 2");
myThread2.start();

The second method: use super to pass the name to the Thread class

//Add construction method
public MyThread(){

}
public MyThread(String name){
    super(name);//Pass name to Thread class with super
}

MyThread myThread = new MyThread("My child thread 1");
MyThread myThread2 = new MyThread("My child thread 2");

Examples

Each class uses 100 inheritance windows to sell 4 tickets

package Thread;

public class TicketWin extends Thread{
    //Add a construction method. After adding, you can simply delete getName
    public TicketWin(){}
    public TicketWin(String name){
        super(name);
    }

    private int ticket = 100;//Number of votes
    @Override
    public void run() {
        //Ticket selling function
        while(true){
            if(ticket<=0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket");
            ticket--;
        }
    }
}
package Thread;

public class TestWin {
    public static void main(String[] args) {

        //Create four windows
        TicketWin w1 = new TicketWin("Window 1");
        TicketWin w2 = new TicketWin("Window 2");
        TicketWin w3 = new TicketWin("Window 3");
        TicketWin w4 = new TicketWin("Window 4");
        //Start thread
        w1.start();
        w2.start();
        w3.start();
        w4.start();
    }
}

Create thread (2)

Second implementation method: Runnable interface

package Thread;

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

public class TestRunnable {
    public static void main(String[] args) {
        //1 create a MyRunnable object to represent the function to be executed
        MyRunnable runnable = new MyRunnable();
        //2 create thread object
        Thread thread = new Thread(runnable,"My thread 1");
        //3 start
        thread.start();
        for (int i = 0;i<50;i++){
            System.out.println("main....."+i);
        }
    }
}

Anonymous Inner Class

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
        for (int i = 0;i<50;i++){
            System.out.println("main....."+i);
               }
            }
        };
        //Create thread object
        Thread thread = new Thread(runnable,"My thread 1");
        thread.start();
    }
}

Runnable case 1

1. Sell 100 tickets in 4 windows

package Thread2;

public class Ticket implements Runnable{
    private int ticket = 100;//100 tickets

    @Override
    public void run() {
        while(true){
            if (ticket<=0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket");
            ticket--;
        }
    }
}
package Thread2;

public class TestTicket {
    public static void main(String[] args) {
        //1 create ticket object
        Ticket ticket = new Ticket();
        //2 create thread object
        Thread w1 = new Thread(ticket,"Window 1");
        Thread w2 = new Thread(ticket,"Window 2");
        Thread w3 = new Thread(ticket,"Window 3");
        Thread w4 = new Thread(ticket,"Window 4");
        //3 start thread
        w1.start();
        w2.start();
        w3.start();
        w4.start();
    }
}

Question: four windows will rob 100 tickets

Runnable case 2

2. You and your girlfriend share a bank card. You deposit money in the card, and your girlfriend withdraws money from the card. Use the program

Simulation process?

Create two classes: deposit and withdraw

package Thread2;

public class AddMoney implements Runnable{
    private BankCard card;//BankCard

    public AddMoney(BankCard card){
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0 ; i<10;i++){
            card.setMoney(card.getMoney()+1000);
            System.out.println(Thread.currentThread().getName()+"Saved 1000,The balance is:"+card.getMoney());
        }
    }
}
package Thread2;

public class SubMoney implements Runnable{
    private BankCard card;
    public SubMoney(BankCard card){
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0;i<10;i++){
            if(card.getMoney()>=1000){
                card.setMoney(card.getMoney()-1000);
                System.out.println(Thread.currentThread().getName()+"After withdrawing 1000, the balance is:"+card.getMoney());
            }else{
                System.out.println("The balance is not enough. Please save money quickly");
                i++;
            }
        }
    }
}

start-up

package Thread2;

public class TestBankCard {
    public static void main(String[] args) {
        //1 create a bank card
        BankCard card = new BankCard();
        //2. Create, save and withdraw money
        AddMoney add = new AddMoney(card);
        SubMoney sub = new SubMoney(card);
        //3 create two threads
        Thread zhangge = new Thread(add,"Brother Zhang");
        Thread jingjing = new Thread(sub,"Quiet");
        //4 start thread
        zhangge.start();
        jingjing.start();
        //Thread safety issues
    }
}

The introduction is written inversely, using anonymous inner classes

package Thread2;

public class TestBankCard2 {
    public static void main(String[] args) {
        BankCard card = new BankCard();
        //save money
        Runnable add = new Runnable() {
            @Override
            public void run() {
                for (int i = 0 ; i<10;i++){
                    card.setMoney(card.getMoney()+1000);
                    System.out.println(Thread.currentThread().getName()+"Saved 1000,The balance is:"+card.getMoney());
                }
            }
        };
        //Withdraw money
        Runnable sub = new Runnable() {
            @Override
            public void run() {
                for (int i = 0;i<10;i++){
                    if(card.getMoney()>=1000){
                        card.setMoney(card.getMoney()-1000);
                        System.out.println(Thread.currentThread().getName()+"After withdrawing 1000, the balance is:"+card.getMoney());
                    }else{
                        System.out.println("The balance is not enough. Please save money quickly");
                        i++;
                    }
                }
            }
        };
        //Create a thread object and start
        new Thread(add,"Clearly").start();
        new Thread(sub,"Xiao Hong").start();
    }
}

Thread status (basic)

Thread sleep

Sleep:

public static void sleep(long millis)

The current thread actively sleeps millis econd

package Thread2;

public class TestSleep extends Thread{
    public static void main(String[] args) {

        SleepThread s1 = new SleepThread();
        s1.start();
        SleepThread s2 = new SleepThread();
        s2.start();

    }
    @Override
    public void run() {
        for (int i = 0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"..."+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }//The subclass cannot throw more exceptions than the parent class. try/catch
        }
    }
}

Waiver:

public static void yield()

The current thread actively abandons the time slice and returns to the ready state to compete for the next time slice.

package Thread2;

public class YieldThread extends Thread{

    @Override
    public void run() {
        for (int i = 0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"..."+i);
            //Actively abandon cpu
            Thread.yield();
        }
    }
}

Thread join:

public final void join()

Allow other threads to join the current thread

j1.join();//Join the current thread (main) and block the current thread until the execution of the join thread is completed
package Thread2;

public class TestJoin extends Thread{
    public static void main(String[] args) {

        
        JoinThread j1 = new JoinThread();
        j1.start();

        try {
            j1.join();//Join the current thread (main) and block the current thread until the execution of the join thread is completed
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //for main thread
        for(int i = 0;i<20;i++){
            System.out.println(Thread.currentThread().getName()+"======"+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        for(int i = 0;i<30;i++){
            System.out.println(Thread.currentThread().getName()+"..."+i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Set thread priority and guard thread

Priority:

Thread object setPriority(),
The thread priority is 1-10, and the default is 5. The higher the priority, the more opportunities to obtain CPU.

Daemon thread:

Thread object setDaemon(true); Set as daemon thread
There are two types of threads: user thread (foreground thread) and daemon thread (background thread).
If all foreground threads in the program are executed, the background thread will automatically end.
The garbage collector thread is a daemon thread.

package Thread2;

public class PriorityThread extends Thread{
    @Override
    public void run() {
        for (int i = 0;i<50;i++){
            System.out.println(Thread.currentThread().getName()+"===="+i);
        }
    }

    public static void main(String[] args) {
        PriorityThread p1 = new PriorityThread();
        p1.setName("p1");
        PriorityThread p2 = new PriorityThread();
        p2.setName("p2");
        PriorityThread p3 = new PriorityThread();
        p3.setName("p3");

        p1.setPriority(1);
        p3.setPriority(10);

        //start-up
        p1.start();
        p2.start();
        p3.start();
    }
}

Daemon thread

package Thread2;

public class TestDeamon {
    public static void main(String[] args) {

        //Create thread (default foreground thread)
        DeamonThread d1 = new DeamonThread();

        //Set as the daemon thread. After the foreground thread (d1) executes, the background thread (main) will end
        d1.setDaemon(true);
        d1.start();

        for (int i = 0;i<10;i++){
            System.out.println("Main thread-------------");
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Status of the thread (waiting)

Thread safety issues

package Thread2;

import java.util.Arrays;

public class ThreadSafe {
    private static int index = 0;
    public static void main(String[] args) throws Exception {
        //Create array
        String[] s = new String[5];
        //Create two operations
        Runnable runnableA = new Runnable() {

            @Override
            public void run() {
                s[index] = "hello";
                index++;
            }
        };
        Runnable runnableB = new Runnable() {
            @Override
            public void run() {
                s[index] = "world";
                index++;
            }
        };
        //Create two thread objects
        Thread a = new Thread(runnableA,"A");
        Thread b = new Thread(runnableB,"B");
        a.start();
        b.start();
        a.join();
        b.join();
        System.out.println(Arrays.toString(s));
    }
}

It is possible that one thread has not finished executing, and another thread has overwritten the result of the previous thread

Thread safety

Synchronization mode

Synchronized (critical resource object) {/ / shackle the critical resource object

//Code (atomic operation), run first

}

Each object has a mutex tag to assign to the thread.
Only the thread with the object mutex flag can enter the synchronous code block that locks the object. When a thread exits a synchronized code block, the corresponding mutex flag is released.

My understanding is that after locking, you have to wait for the code (atomic operation) to complete before you have the next operation

After locking, other threads can only run after the running code is completed

Runnable runnableA = new Runnable() {

    @Override
    public void run() {
        //Synchronous code block
        synchronized (s){
            s[index] = "hello";
            index++;
        }
    }
};
Runnable runnableB = new Runnable() {
    @Override
    public void run() {
        synchronized (s){
            s[index] = "world";
            index++;
        }
    }
};

Synchronous code block usage (1)

@Override
public void run() {
    while(true){
        if (ticket<=0){
            break;
        }
        System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket");
        ticket--;
    }
}

Analysis: there are 4 windows and 100 tickets. If the first window will execute after getting the CPU and sell the 100th ticket, but there may be no ticket --, the time segment will arrive. At this time, the ticket is still 100, and at this time, the second window will get the CPU and sell the 100th ticket, and so on, there will be repetition.

public class Ticket implements Runnable{
    private int ticket = 100;//100 tickets
    //Create lock
    private Object obj = new Object();

    @Override
    public void run() {
        while(true){
            synchronized (obj){
                if (ticket<=0){
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket");
            ticket--;
        }
    }
}

You cannot create an object at the critical resource object in the lock, synchronized(new Object()), which means that each thread creates a lock every time it comes in. It is equivalent to a house. A person (thread) can only have one lock. After it is used up, another person (thread) can be changed. If a lock is created, other people (thread) will still enter.

sure

private int obj = new Object();

synchronized(new Object())

it's fine too

synchronized(this);

this is the ticket and the only one

Synchronous code block usage (2)

package Thread2;

public class TestBankCard {
    public static void main(String[] args) {
        BankCard card = new BankCard();
        Object obj =new Object();
        //save money
        Runnable add = new Runnable() {
            @Override
            public void run() {
                    for (int i = 0 ; i<10;i++){
                        synchronized (obj){
                        card.setMoney(card.getMoney()+1000);
                        System.out.println(Thread.currentThread().getName()+"Saved 1000,The balance is:"+card.getMoney());
                    }
                }
            }
        };
        //Withdraw money
        Runnable sub = new Runnable() {
            @Override
            public void run() {
                for (int i = 0;i<10;i++){
                    synchronized (obj){
                        if(card.getMoney()>=1000){
                            card.setMoney(card.getMoney()-1000);
                            System.out.println(Thread.currentThread().getName()+"After withdrawing 1000, the balance is:"+card.getMoney());
                        }else{
                            System.out.println("The balance is not enough. Please save money quickly");
                            i--;
                        }
                    }
                }
            }
        };
        new Thread(add,"Clearly").start();
        new Thread(sub,"Xiao Hong").start();
    }
}

Synchronization method

Synchronization method:
synchronized return value type method name (parameter list 0) {/ / lock the current object (this)

//Code (atomic operation)

}

Only the thread with the mutex mark of the object can enter the synchronization method of locking the object.

When the thread exits the synchronization method, the corresponding mutex flag is released.

public class Ticket implements Runnable {
    private int ticket = 100;//100 tickets
    //Create lock
    //private Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            if(!sale()){
                break;
            }
        }
    }
    //Selling tickets
    public synchronized boolean sale() {//Lock this static method to lock ticket class
        if (ticket <= 0) {
            return false;
        }
        System.out.println(Thread.currentThread().getName() + "Bought the second" + ticket + "Ticket");
        ticket--;
        return true;
    }
}

Synchronization rules

be careful:
The lock mark of the object is required only when calling a method containing a synchronized code block or a synchronized method.

If you call a method that does not contain a synchronous code block or an ordinary method, you do not need a lock mark and can call it directly.

Known thread safe classes in JDK:
StringBuffer

Vector

Hashtable

The disclosed methods in the above classes are synchronous methods modified by synchronized.

deadlock

Deadlock:

A deadlock occurs when the first thread has the a object lock mark and waits for the B object lock mark, while the second thread has the B object lock mark and waits for the a object lock mark.

A thread can have lock marks of multiple objects at the same time. When the thread is blocked, it will not release the lock marks it already has, which may cause deadlock.

public class Boy extends Thread{
    @Override
    public void run() {
        synchronized (MyLock.a) {
            System.out.println("The boy got it a");
            synchronized (MyLock.b) {
                System.out.println("The boy got it b");
                System.out.println("The boy can eat");
            }
        }
    }
}
public class Girl extends Thread{
    @Override
    public void run() {
        synchronized (MyLock.b) {
            System.out.println("The girl got it b");
            synchronized (MyLock.a) {
                System.out.println("The girl got it a");
                System.out.println("The girl can eat");
            }
        }
    }
}
public class MyLock extends Thread{
    public static Object a = new Object();
    public static Object b = new Object();

    public static void main(String[] args) {
        Boy boy = new Boy();
        Girl girl = new Girl();
        boy.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        girl.start();
    }
}

Thread communication

Wait:
public final void wait()

public final void wait(long timeout)

It must be in the synchronization code block that locks obj. In a thread, call obj.. When waiting(), this thread
Put all the lock marks it has. At the same time, this thread is blocked in o's waiting queue. Release the lock and enter the waiting queue.

Notice:

public final void notify()

public final void notifyAl1()

Deposit and withdraw money

Add

package Thread3;

public class Add implements Runnable{
    private BankCard card;
    //structure
    public Add(BankCard card){
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0;i<10;i++){
            card.save(1000);

        }
    }
}

Sub

package Thread3;

public class Sub implements Runnable{
    private BankCard card;
    public Sub (BankCard card){
        this.card = card;
    }
    @Override
    public void run() {
        for (int i = 0;i<10;i++){
            card.take(1000);

        }
    }
}

BankCard

package Thread3;

public class BankCard {
    //balance
    private double money;
    //sign
    private boolean flag = false;//True means you can withdraw money if you have money, false means you can withdraw money if you have no money

    //save money
    public synchronized void save(double m){//Lock this
        if (flag) {//rich
            try {
                this.wait();//Enter the waiting queue, and the colleague releases the lock and cpu
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money = money +m;
        System.out.println(Thread.currentThread().getName()+"Saved"+m+"The balance is"+money);
        //Modify tag
        flag = true;
        //Wake up the money withdrawal thread
        this.notify();
    }

    //Withdraw money
    public synchronized void take(double m ){
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money = money - m;
        System.out.println(Thread.currentThread().getName()+"Yes"+m+"The balance is"+money);
        flag = false;
        //Wake up and save money
        this.notify();
    }
}

Test

package Thread3;

public class TestBankCard {
    public static void main(String[] args) {
        //1 create a bank card
        BankCard card = new BankCard();
        //2 create operation
        Add add = new Add(card);
        Sub sub = new Sub(card);

        //3 create thread object
        Thread chenchen = new Thread(add,"Morning morning");
        Thread bingbing = new Thread(sub,"Bingbing");
        //4 start
        chenchen.start();
        bingbing.start();
    }
}

Analysis of multi storage capture problem

Will disorder

public class BankCard {
    //balance
    private double money;
    //sign
    private boolean flag = false;//True means you can withdraw money if you have money, false means you can withdraw money if you have no money

    //save money
    public synchronized void save(double m){//Lock this
        while (flag) {//If you have money, the default is true first?
            try {
                this.wait();//Enter the waiting queue, and the colleague releases the lock and cpu
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money = money +m;
        System.out.println(Thread.currentThread().getName()+"Saved"+m+"The balance is"+money);
        //Modify tag
        flag = true;
        //Wake up the money withdrawal thread
        this.notify();
    }

    //Withdraw money
    public synchronized void take(double m ){
        while (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money = money - m;
        System.out.println(Thread.currentThread().getName()+"Yes"+m+"The balance is"+money);
        flag = false;
        //Wake up and save money
        this.notify();
    }
}

Replace if with while, which can be disordered

But it is also possible that all four threads are waiting

notify(); Change to notifyAll();

After all wakes up, whlie, the qualified ones enter the cycle

Problem solving

bounded-buffer problem

Producers and consumers:
Several producers are producing products, which will be provided to several consumers for consumption. In order to enable producers and consumers to execute concurrently, a buffer zone that can store multiple products is set between them. The producers put the produced products into the buffer zone, and consumers take the products from the buffer zone for consumption, Obviously, producers and consumers must keep synchronization, that is, consumers are not allowed to get products from an empty buffer, nor are producers allowed to put products into a full buffer.

Bread

package Thread3;

public class Bread {
    private int id ;
    private String productName;
    public Bread(){

    }
    public Bread(int id, String productName) {
        this.id = id;
        this.productName = productName;
    }



    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }


    @Override
    public String toString() {
        return "Bread{" +
                "id=" + id +
                ", productName='" + productName + '\'' +
                '}';
    }
}

Producer class

package Thread3;

public class Product implements Runnable{
    private BreadCon con;

    public Product(BreadCon con){
        super();
        this.con = con;
    }

    @Override
    public void run() {
        for (int i = 0;i<30;i++){
            con.input(new Bread(i,Thread.currentThread().getName()));
        }
    }
}

Consumer category

package Thread3;

public class Consume implements Runnable{
    private BreadCon con;

    public Consume(BreadCon con){
        super();
        this.con = con;
    }

    @Override
    public void run() {
        for (int i = 0;i < 30;i++){
            con.output();
        }
    }
}

Bread containers

package Thread3;

public class BreadCon {
    //An array of bread
    private Bread[] cons = new Bread[6];
    //Where to store bread
    private int index = 0;

    public synchronized void input(Bread b){//Lock this
        //Judge whether the container is full
        while(index>=6){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        cons[index]=b;
        System.out.println(Thread.currentThread().getName()+"Produced"+b.getId()+"");
        index++;
        this.notifyAll();
    }
    //Take out the bread
    public synchronized void output(){//Lock this
        while(index<=0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        index--;
        Bread b = cons[index];
        System.out.println(Thread.currentThread().getName()+"Consumption"+b.getId()+"producer"+b.getProductName());
        cons[index] = null;
        //Wake up producers
        this.notifyAll();
    }
}

Test class

package Thread3;

public class Test {
    public static void main(String[] args) {

    //container
    BreadCon con = new BreadCon();
    //Production and consumption
    Product product = new Product(con);
    Consume consume = new Consume(con);
    //Create thread object
    Thread chenchen = new Thread(product,"Morning morning");
    Thread bingbing = new Thread(consume,"consumption");
    //Start thread
    chenchen.start();
    bingbing.start();
    }
}

Keywords: Java Multithreading

Added by pedrolopes10 on Sun, 20 Feb 2022 19:12:20 +0200