Detailed explanation of Java multithreading

Processes and threads


Example code:

package com.gavin.demo01;

public class TestThread extends Thread{

    @Override
    public void run() {
        //run cube thread
        for (int i = 0; i < 20; i++) {
            System.out.println("I'm looking at the code---" + i);
        }
    }

    public static void main(String[] args) {
        //The main method is a main thread
        //Create a thread object
        TestThread testThread = new TestThread();
        //Call the start method to start the thread
        testThread.start();
        for (int i = 0; i < 1000 ; i++) {
            System.out.println("I'm learning multithreading---" + i);
        }
    }
}

Execution results:

It can be seen that the run method and the main method are executed at the same time and are scheduled by the CPU, resulting in the problem of thread preemption
Sample code for downloading pictures using multithreading:

package com.gavin.demo01;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestThread2 extends Thread{

    private String url;

    private String name;

    public TestThread2(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownLoad webDownLoad = new WebDownLoad();
        webDownLoad.down(url, name);
        System.out.println("The downloaded file is:" + name);
    }

    public static void main(String[] args) {
        TestThread2 testThread = new TestThread2("https://img-blog.csdnimg.cn/ff1034bf4ec944ed9b9fefb5d9bbeb2c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "1.jpg");
        TestThread2 testThread2 = new TestThread2("https://img-blog.csdnimg.cn/98a80c1487354509baa94b1522e22fe6.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "2.jpg");
        TestThread2 testThread3 = new TestThread2("https://img-blog.csdnimg.cn/30244b9ad1eb40d6a2c6f757e458d343.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "3.jpg");
        testThread.start();
        testThread2.start();
        testThread3.start();
    }
}

class WebDownLoad{

    public void down(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO Abnormal, down Method error");
        }
    }
}

Execution results:

It can be seen that after the program is started, the three threads are executed at the same time, not in the order from top to bottom, so the printing order shown in the figure appears.

Implement Runnable interface


Example code:

package com.gavin.demo01;

public class TestRunnable implements Runnable{
    @Override
    public void run() {
        //run method thread
        for (int i = 0; i < 20; i++) {
            System.out.println("I'm looking at the code---" + i);
        }
    }

    public static void main(String[] args) {
        //The main method is a main thread
        //Create a thread object
        TestRunnable testRunnable = new TestRunnable();
        //Pass in the class that implements the Runnable interface
        Thread thread = new Thread(testRunnable);
        //Call the start method to start the thread
        thread.start();
        for (int i = 0; i < 1000 ; i++) {
            System.out.println("I'm learning multithreading---" + i);
        }
    }
}

Execution results:

Use the Runnable interface to download images
Example code:

package com.gavin.demo01;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestRunnable2 implements Runnable{
    private String url;

    private String name;

    public TestRunnable2(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownLoad2 webDownLoad2 = new WebDownLoad2();
        webDownLoad2.down(url, name);
        System.out.println("The downloaded file is:" + name);
    }
    public static void main(String[] args) {
        TestThread2 testThread = new TestThread2("https://img-blog.csdnimg.cn/ff1034bf4ec944ed9b9fefb5d9bbeb2c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "1.jpg");
        TestThread2 testThread2 = new TestThread2("https://img-blog.csdnimg.cn/98a80c1487354509baa94b1522e22fe6.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "2.jpg");
        TestThread2 testThread3 = new TestThread2("https://img-blog.csdnimg.cn/30244b9ad1eb40d6a2c6f757e458d343.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "3.jpg");
        Thread thread = new Thread(testThread);
        Thread thread2 = new Thread(testThread2);
        Thread thread3 = new Thread(testThread3);
        thread.start();
        thread2.start();
        thread3.start();
    }
}

class WebDownLoad2{

    public void down(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO Abnormal, down Method error");
        }
    }
}

Execution results:

Understanding concurrency problems

Example code for multithreading to operate the same object:

package com.gavin.Demo02;

//Multithreading operates on an object at the same time
//Example of buying a train ticket
public class TestRunnable3 implements Runnable{

    //Number of votes
    private int ticketNumber = 10;

    @Override
    public void run() {
        while (true) {
            if (ticketNumber <= 0) {
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->Got the second" + ticketNumber-- + "Ticket");
        }
    }

    public static void main(String[] args) {
        TestRunnable3 testRunnable = new TestRunnable3();
        Thread thread = new Thread(testRunnable, "Xiao Ming");
        thread.start();
        Thread thread2 = new Thread(testRunnable, "teacher");
        thread2.start();
        Thread thread3 = new Thread(testRunnable, "Scalpers");
        thread3.start();
    }

}

Execution results:

It can be seen that Xiao Ming and the scalpers grabbed the 9th ticket at the same time, and Xiao Ming and the teacher grabbed the 5th ticket at the same time. There is a big problem, which needs to be solved with concurrent knowledge in the future.

Tortoise rabbit race example

Example code:

package com.gavin.Demo02;

//Example of simulated tortoise rabbit race
public class Race implements Runnable{

    private static String winner;

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            //Let the rabbit rest for 5 milliseconds
            if (Thread.currentThread().getName().equals("rabbit") && i % 10 == 0) {
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "-->Run away" + i + "step");
            Boolean flag = gameOver(i);
            if (flag) {
                break;
            }
        }
    }

    public Boolean gameOver(int steps) {
        if (winner != null) {
            return true;
        } else {
            if (steps >= 100) {
                winner = Thread.currentThread().getName();
                System.out.println("The winners are:" + winner);
                return true;
            }
        }
        return false;
    }

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

Execution results:

With a piece of code to restore the classic tortoise and rabbit race story, it is true and good!

Implement Callable interface


Example code:

package com.gavin.Demo02;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//Implement the Callable interface to download pictures
public class TestCallable implements Callable<Boolean> {

    private String url;

    private String name;

    public TestCallable(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public Boolean call() throws Exception {
        WebDownLoad2 webDownLoad = new WebDownLoad2();
        webDownLoad.down(url, name);
        System.out.println("The downloaded file is:" + name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable testCallable = new TestCallable("https://img-blog.csdnimg.cn/ff1034bf4ec944ed9b9fefb5d9bbeb2c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "1.jpg");
        TestCallable testCallable2 = new TestCallable("https://img-blog.csdnimg.cn/98a80c1487354509baa94b1522e22fe6.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "2.jpg");
        TestCallable testCallable3 = new TestCallable("https://img-blog.csdnimg.cn/30244b9ad1eb40d6a2c6f757e458d343.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAR2F2aW5DaGVuXw==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center", "3.jpg");
        //Create execution service
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //Submit for execution
        Future<Boolean> r1 = executorService.submit(testCallable);
        Future<Boolean> r2 = executorService.submit(testCallable2);
        Future<Boolean> r3 = executorService.submit(testCallable3);
        //Get results
        boolean rs1 = r1.get();
        boolean rs2 = r1.get();
        boolean rs3 = r1.get();
        System.out.println(rs1);
        System.out.println(rs2);
        System.out.println(rs3);
        //Shut down service
        executorService.shutdown();
    }
}
class WebDownLoad2{

    public void down(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO Abnormal, down Method error");
        }
    }
}

Execution results:

Static proxy mode

Example code:

package com.gavin.Demo03;

public class StaticProxy {

    public static void main(String[] args) {
        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.HappyMarry();
    }

}

interface Marry {

    void HappyMarry();
}

class You implements Marry {

    @Override
    public void HappyMarry() {
        System.out.println("Today Happy oh");
    }
}

class WeddingCompany implements Marry {

    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }

    public void before() {
        System.out.println("yesterday Happy!!!");
    }

    public void after() {
        System.out.println("tomorrow Happy!!!");
    }
}

Execution results:

It can be seen that WeddingCompany, as a static proxy of You class, can call not only its own methods, but also the methods of proxy objects. This is the idea of static proxy.

Thread state

Thread stop

Use your own defined method to stop the thread

Example code:

package com.gavin.Demo04;

public class TestStop implements Runnable{

    //Set an ID to stop the thread
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("Yes-->" + i++ + "second");
        }
    }

    //Set an open method to stop the thread and convert the flag bit
    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        Thread thread = new Thread(testStop);
        thread.start();
        for (int i = 0; i <= 100 ; i++) {
            System.out.println("main Yes-->" + i + "second");
            if (i == 90) {
                //Call your own stop method to stop the thread
                testStop.stop();
                System.out.println("The thread has stopped");
            }
        }

    }
}

Execution results:

It can be seen that when the main thread is executed for the 90th time, the user-defined thread stop method is called to stop the user-defined thread. At this time, the user-defined thread is executed only 63 times.

Thread sleep


Use thread The sleep method completes the countdown function
Example code:

package com.gavin.Demo04;

public class TestSleep {

    public static void main(String[] args) {
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //Use thread The sleep method completes the countdown function
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while (true) {
            Thread.sleep(1000);
            System.out.println(num);
            num --;
            if (num == 0) {
                break;
            }
        }
    }
}

Execution results:

Use thread The sleep method prints the current system time
Example code:

package com.gavin.Demo04;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep2 {

    //Use thread The sleep method prints the current system time
    public static void main(String[] args) throws InterruptedException {
        Date startTime = new Date(System.currentTimeMillis());
        while (true) {
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
            startTime = new Date(System.currentTimeMillis());
        }
    }
}

Execution results:

Thread comity


Example code:

package com.gavin.Demo04;

public class TestYield {

    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        Thread thread = new Thread(myYield, "a");
        Thread thread2 = new Thread(myYield, "b");
        thread.start();
        thread2.start();
    }
}

class MyYield implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "Thread starts execution");
        //Thread comity
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + "Thread stop execution");
    }
}

Execution results:

It can be seen that thread a gives way to thread b when the program is executing

Thread enforcement


Example code:

package com.gavin.Demo04;

public class TestJoin implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("thread  VIP coming-->" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();
        //The main thread starts executing
        for (int i = 1; i <= 500; i++) {
            if (i == 20) {
                //Thread queue jumping
                thread.join();
            }
            System.out.println("main-->" + i);
        }
    }
}

Execution results:

Observe thread status


Example code:

package com.gavin.state;

public class TestState {

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("//");
        });

        //Observe thread status
        Thread.State state = thread.getState();
        System.out.println(state);      //NEW

        //Observe the status after thread startup
        thread.start();
        state = thread.getState();
        System.out.println(state);      //RUN

        //As long as the thread does not terminate, it will always output state
        while (state != Thread.State.TERMINATED) {
            try {
                Thread.sleep(100);
                //Update thread status
                state = thread.getState();
                //Output status
                System.out.println(state);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Execution results:

thread priority


Example code:

package com.gavin.state;

public class TestPriority {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
        MyPriority myPriority = new MyPriority();
        Thread thread = new Thread(myPriority);
        Thread thread2 = new Thread(myPriority);
        Thread thread3 = new Thread(myPriority);
        Thread thread4 = new Thread(myPriority);
        Thread thread5 = new Thread(myPriority);
        Thread thread6 = new Thread(myPriority);
        //Set the priority of the thread before starting the thread
        thread.start();
        thread2.setPriority(3);
        thread2.start();
        thread3.setPriority(Thread.MAX_PRIORITY);   //Thread.MAX_PRIORITY = 10
        thread3.start();
        thread4.setPriority(Thread.MIN_PRIORITY);   //Thread.MIN_PRIORITY = 1
        thread4.start();
        thread5.setPriority(7);
        thread5.start();
        thread6.setPriority(8);
        thread6.start();
    }
}

class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
    }
}

Execution results:

It can be seen that sometimes the execution order of threads is not executed according to the set priority. This is because the CPU operation speed is very fast and the CPU algorithm is optimized. These threads execute almost at the same time, and all printed priorities are not the priority set by themselves.

Daemon thread


Example code:

package com.gavin.state;

public class TestDaemon {

    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread thread = new Thread(god);
        //The default is false, which means that it is a user thread. Normal threads are user threads
        thread.setDaemon(true);
        //God hand guard thread on
        thread.start();
        Thread thread2 = new Thread(you);
        //Own user thread
        thread2.start();
    }
}

class God implements Runnable {

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

class You implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("Live happily every day!");
        }
        System.out.println("Farewell to the world! GoodBy~~~");
    }
}

Execution results:

Thread synchronization mechanism

Concurrent interpretation:

Explanation of thread lock:

Thread unsafe cases

Bank withdrawal cases
Example code:

package com.gavin.syn;

public class UnsafeBank {

    public static void main(String[] args) {
        Account account = new Account("Marriage fund", 100);
        Drawing drawing = new Drawing(account, 50, "you");
        Drawing drawing2 = new Drawing(account, 100, "Your daughter-in-law");
        drawing.start();
        drawing2.start();
    }
}

class Account {
    String name;

    int balance;

    public Account(String name, int balance) {
        this.name = name;
        this.balance = balance;
    }
}

class Drawing extends Thread {

    Account account;
    //How much did you withdraw
    int drawingMoney;
    //How much money do you have now
    int nowMoney;

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        if (account.balance - drawingMoney < 0) {
            System.out.println(Thread.currentThread().getName() + "There's not enough money to withdraw");
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Card balance
        account.balance =  account.balance - drawingMoney;
        //The money in your hand
        nowMoney = nowMoney + drawingMoney;
        System.out.println(account.name + "The balance is:" + account.balance);
        System.out.println(this.getName() + "Money in hand:" + nowMoney);
    }
}

Execution results:

It can be seen that two threads withdraw money at the same time, and the balance becomes negative, resulting in major problems.

synchronized synchronization method


Optimize the ticket grabbing code with synchronized:

package com.gavin.Demo02;

//Multithreading operates on an object at the same time
//Example of buying a train ticket
public class TestRunnable3 implements Runnable{

    //Number of votes
    private int ticketNumber = 10;

    @Override
    public synchronized void run() {
        while (true) {
            if (ticketNumber <= 0) {
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->Got the second" + ticketNumber-- + "Ticket");
        }
    }

    public static void main(String[] args) {
        TestRunnable3 testRunnable = new TestRunnable3();
        Thread thread = new Thread(testRunnable, "Xiao Ming");
        thread.start();
        Thread thread2 = new Thread(testRunnable, "teacher");
        thread2.start();
        Thread thread3 = new Thread(testRunnable, "Scalpers");
        thread3.start();
    }

}

Execution results:

synchronized synchronization block


Optimize bank withdrawal codes using synchronized synchronization blocks:

package com.gavin.syn;

public class UnsafeBank {

    public static void main(String[] args) {
        Account account = new Account("Marriage fund", 100);
        Drawing drawing = new Drawing(account, 50, "you");
        Drawing drawing2 = new Drawing(account, 100, "Your daughter-in-law");
        drawing.start();
        drawing2.start();
    }
}

class Account {
    String name;

    int balance;

    public Account(String name, int balance) {
        this.name = name;
        this.balance = balance;
    }
}

class Drawing extends Thread {

    Account account;
    //How much did you withdraw
    int drawingMoney;
    //How much money do you have now
    int nowMoney;

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        synchronized (account) {
            if (account.balance - drawingMoney < 0) {
                System.out.println(Thread.currentThread().getName() + "There's not enough money to withdraw");
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Card balance
            account.balance =  account.balance - drawingMoney;
            //The money in your hand
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.name + "The balance is:" + account.balance);
            System.out.println(this.getName() + "Money in hand:" + nowMoney);
        }
    }
}

Execution results:

CopyOnWriteArrayList collection

The CopyOnWriteArrayList collection is thread safe. See the following example code for details:

package com.gavin.syn;

import java.util.concurrent.CopyOnWriteArrayList;

public class TestJUC {

    public static void main(String[] args) {
        CopyOnWriteArrayList<String> arrayList = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                arrayList.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("CopyOnWriteArrayList The set length is:" + arrayList.size());
    }
}

Execution results:

deadlock


Example code:

package com.gavin.thread;

public class DeadLock {

    public static void main(String[] args) {
        Makeup makeup = new Makeup(0, "Xiaolan");
        Makeup makeup2 = new Makeup(1, "Xiaomei");
        makeup.start();
        makeup2.start();
    }
}

//Lipstick
class Lipstick {

}
//Mirror class
class Mirror {

}
class Makeup extends Thread {
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    int choice;
    String girlName;

    Makeup(int choice, String girlName) {
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void makeup() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipstick) {
                System.out.println(this.girlName + "Get lipstick");
                Thread.sleep(1000);
                synchronized (mirror) {
                    System.out.println(this.girlName + "Get the mirror");
                }
            }
        } else {
            synchronized (mirror) {
                System.out.println(this.girlName + "Get the mirror");
                Thread.sleep(2000);
                synchronized (lipstick) {
                    System.out.println(this.girlName + "Get lipstick");
                }
            }
        }
    }
}

Execution results:

It can be seen that the program has entered a deadlock state

Four necessary conditions for deadlock generation:

Lock lock


Example code:

package com.gavin.thread;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();
        Thread thread = new Thread(testLock2);
        Thread thread2 = new Thread(testLock2);
        Thread thread3 = new Thread(testLock2);
        thread.start();
        thread2.start();
        thread3.start();
    }
}

class TestLock2 implements Runnable {

    int tickNumber = 10;

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

    @Override
    public void run() {
        while (true) {
            try {
                //Lock
                reentrantLock.lock();
                if (tickNumber > 0) {
                    System.out.println("Number of votes remaining:" + tickNumber --);
                } else {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //Unlock after thread execution
                reentrantLock.unlock();
            }
        }
    }
}

Execution results:

Differences between synchronized and Lock locks:

Producer and consumer issues



Application scenario:

Pipe program method


Example code:

package com.gavin.thread;


public class TestPC {

    public static void main(String[] args) {
        SynContainer synContainer = new SynContainer();
        Product product = new Product(synContainer);
        Customer customer = new Customer(synContainer);
        product.start();
        customer.start();
    }
}

class Product extends Thread {

    SynContainer synContainer;

    Product(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

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

class Customer extends Thread {

    SynContainer synContainer;

    Customer(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

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

class Chicken {

    int id;

    Chicken(int id) {
        this.id = id;
    }
}

class SynContainer {

    Chicken[] chickens = new Chicken[10];

    int count = 0;

    public synchronized void push(Chicken chicken) {
        //If the container is full, wait for the consumer to consume
        if (count == chickens.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        chickens[count] = chicken;
        count++;
        //Consumers can be informed of consumption
        this.notifyAll();
    }

    public synchronized Chicken pop() {
        //No, just wait for the producer to produce
        if (count == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //Consumption when there is
        count--;
        Chicken chicken = chickens[count];
        //Inform the producer of production
        this.notifyAll();
        return chicken;
    }
}

Execution results:

Signal lamp method:


Example code:

package com.gavin.thread;

public class TestPC2 {

    public static void main(String[] args) {
        TV tv = new TV();
        Player player = new Player(tv);
        Watcher watcher = new Watcher(tv);
        player.start();
        watcher.start();
    }
}

class Player extends Thread{

    TV tv;

    Player(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i % 2 == 0) {
                this.tv.play("B station");
            } else {
                this.tv.play("Tiktok");
            }
        }
    }
}

class Watcher extends Thread{
    TV tv;

    Watcher(TV tv) {
        this.tv = tv;
    }

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

class TV {

    //Name of the show
    String voice;

    //Actor performance logo
    boolean flag = true;

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

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

}

Execution results:

Thread pool


Example code:

package com.gavin.thread;

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

public class TestPool {

    public static void main(String[] args) {
        //Create 10 threads
        ExecutorService service = Executors.newFixedThreadPool(10);
        //Execution thread
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //Close thread
        service.shutdown();
    }

}

class MyThread implements Runnable {

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

Execution results:

summary

Three ways to create threads
Example code:

package com.gavin.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadNew {

    public static void main(String[] args) {
        new MyThread1().start();
        new Thread(new MyThread2()).start();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
        new Thread(futureTask).start();
        try {
            Integer number = futureTask.get();
            System.out.println(number);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class MyThread1 extends Thread {

    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}

class MyThread2 implements Runnable {

    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}

class MyThread3 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}

Execution results:

Keywords: Java

Added by brendan2b on Wed, 19 Jan 2022 10:10:20 +0200