Multithreaded notes

Multithreading

1. Basic concepts

Process and Thread

Program: an ordered collection of instructions and data. It has no running meaning. It is a static concept.

Process: it is an execution process of an executing program. It is a dynamic concept. It is the unit of system resource allocation.

A process can contain multiple threads (for example, you can hear sound, see images, and watch bullet screens in the video at the same time)

A process has at least one thread, otherwise it has no meaning to exist.

Thread: the unit of CPU scheduling and execution.

Note: many multithreads are simulated. Real multithreading refers to having multiple CPUs, i.e. multiple cores, such as servers. If it is a simulated multithreading, that is, in the case of one CPU, the CPU can only execute one code at the same time point. Because the switching is fast, there is the illusion of simultaneous execution.

2. Core concepts

  • Threads are independent execution paths;
  • When the program is running, even if it does not create its own thread, there will be multiple threads in the background, such as main thread and gc thread;
  • main() is called the main thread, which is the entry of the system and is used to execute the whole program;
  • In a process, if multiple threads are opened up, the operation of threads is scheduled by the scheduler. The scheduler is closely related to the operating system, and the sequence can not be interfered by human beings;
  • When operating on the same resource, there will be a problem of resource grabbing, and concurrency control needs to be added;
  • Threads will bring additional overhead, such as CPU scheduling time and concurrency control overhead;
  • Each thread interacts in its own working memory. Improper memory control will cause data inconsistency

3. Thread creation

  1. Inherit the Thread class and override the run method
    • Create Thread class
    • Override the run() method
    • Call start() to start the thread
//Thread creation method 1: inherit the thread class, rewrite the run() method, and call start() to start the thread
public class Test01 extends Thread{

	@Override
	public void run() {
		//run method thread body
		for (int i = 0; i <20; i++) {
			System.out.println("I'm looking at the code");
		}
		
	}
	public static void main(String[] args) {
		//main thread
		
		//Create a thread object
		Test01 t= new Test01();
//		t.run();      Call the run () method, execute the run method body, and then execute the main method body
		//Call the start() method to start the thread and execute at the same time
		t.start();
		
		for (int i = 0; i < 2000; i++) {
			System.out.println("I'm learning multithreading"+i);
		}
	}
}

Summary: thread startup is not necessarily executed immediately, but is scheduled by the CPU

  1. Implement Runnable interface

a. Implement Runnable interface

b. Override the run() method

c. The execution thread needs to create a runnable interface implementation class and call the start() method

public class Test02 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("Run thread" + i);
        }
    }

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

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

Buy a train ticket

public class TestTread implements Runnable {
    //Number of votes
    private int ticketNums = 10;

    @Override
    public void run() {
        while(true){
            if(ticketNums<=0){
                break;
            }

            //Analog delay
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticketNums-- +"ticket");
        }

    }

    public static void main(String[] args) {
        TestTread ticket = new TestTread();

        new Thread(ticket,"Xiao Ming").start();
        new Thread(ticket,"teacher").start();
        new Thread(ticket,"cattle").start();
    }
}

Image download [use Maven project, do not download common IO package]

public class WebDownloader implements Runnable {

    private String url;
    private String name;


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

    public void run() {
        DownLoadeer downLoadeer = new DownLoadeer();
        downLoadeer.Down(url,name);
        System.out.println("Printed" + name);
    }

    public static void main(String[] args) {
        WebDownloader webDownloader1 = new WebDownloader("https://img14.360buyimg.com/n0/jfs/t1/55022/14/17084/127324/613598e6E8645c385/20fa4394e07e7506.jpg "," mouse. jpg ");
        WebDownloader webDownloader2 = new WebDownloader("https://Img14.360buyimg. COM / N0 / JFS / T1 / 6521 / 19 / 15591 / 164485 / 6157279e424120d1 / 6d9a67ac840a4271. jpg "," flat plate. jpg ");
        WebDownloader webDownloader3 = new WebDownloader("https://img14.360buyimg.com/n0/jfs/t1/164028/13/19810/141210/607d328aE3b9319a1/b3a14384c998ebd2.jpg "," mobile phone. jpg ");

        new Thread(webDownloader1).start();
        new Thread(webDownloader2).start();
        new Thread(webDownloader3).start();
    }
}

class DownLoadeer{
    public void Down(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("io Abnormal, Down There is a problem with the method");
        }
    }
}

Summary: the difference between the above two

  1. Inherit Thread class:
  • The subclass inherits the Thread class and has multithreading capability
  • Start thread: subclass object. start()
  • Not recommended: avoid the limitation of OOP single inheritance
  1. Implement Runnable interface:
  • The implementation of Runnable interface has multithreading capability
  • Start thread: new thread (implementation class object). start()
  • Recommended: avoid the limitation of single inheritance and make it convenient for the same object to be used by multiple threads
  1. Implement Callable interface
  • Implement Calleble interface
  • Override call() method
  • Create execution service
ExecutorService ser = Executors.newFixedThreadPool(Number of threads);
  • Submit for execution
Future<return type> r = ser.submit(Thread name);
  • Get results
type res=r.get();
  • Shut down service
ser.shutdownNow();

Summary:

Advantages: 1. Return value can be defined; 2. Exception can be thrown

Disadvantages: relatively troublesome

4. Static proxy

——Multithreading underlying implementation principle

Example: real role: you; agent role: wedding company; marriage: realize marriage interface

public class StaticProxy {
    public static void main(String[] args) {
        WeddingCompany company = new WeddingCompany(new You());
        company.happyMarry();
    }

}

interface Marry{
    void happyMarry();
}

//Real role
class You implements Marry{

    @Override
    public void happyMarry() {
        System.out.println("I'm so happy to be married!");
    }
}

//Acting role to help you get married
class WeddingCompany implements Marry{

    private Marry target;

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

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

    }

    private void after() {
        System.out.println("After marriage, the final payment");

    }

    private void before() {
        System.out.println("Before marriage, arrange the scene");
    }

}

Summary: both real objects and proxy objects should implement the same interface, and proxy objects should represent real roles

Advantages: proxy objects can do many things that real objects can't do

Real objects focus on their own things

In combination with threads:

new Thread(t).start();
new WeddingCompany(new You()).happyMarry();

Runnable - > Mary interface

Thread - > weddingcompany is the agent

t -- > New you() target object (real character)

5. Lambda expression

  • In essence, it belongs to the concept of functional programming
1. Function
  • Avoid too many anonymous inner class definitions
  • Make the code look simple
  • Simplify the code, leaving only the core logic
2. Functional interface

Definition: any interface that contains only one abstract method is a functional interface

public interface Runnable{
   public abstract void run();
}

For functional interfaces, we can create objects of the interface through lambda expressions

3. Simple derivation of lambda
/**
 * Derivation of Lambda expressions
 * @author DELL
 *
 */
public class TestLambda {

    //3. Static internal class
    static class Like2 implements Ilike{

        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }

    public static void main(String[] args) {
        Ilike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();

        //4. Local internal class
        class Like3 implements Ilike{

            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        }

        like = new Like3();
        like.lambda();

        //5. Anonymous inner class
        like = new Ilike() {

            @Override
            public void lambda() {
                System.out.println("i like lambda5");
            }
        };

        like.lambda();

        //6. Simplify with lambda
        like = ()->{
            System.out.println("i like lambda5");
        };
        like.lambda();
    }
}

//1. Define a functional interface
interface Ilike{
    void lambda();
}

//2. Implementation class
class Like implements Ilike{

    @Override
    public void lambda() {
        System.out.println("i like lambda");

    }

}
public class TestLambda2 {

    public static void main(String[] args) {
        ILove  love = null;
        //1.lambda stands for simplification
        love = (int a)->{
            System.out.println("LOvee"+ a);
        };

        //Simplification 1: parameter type
        love = (a)->{
            System.out.println("LOvee"+ a);
        };

        //Simplify 2: simplify parentheses
        love = a->{
            System.out.println("LOvee"+ a);
        };

        //Simplify 3: simplify curly braces
        love = a-> System.out.println("LOvee"+ a);

        love.love(205);
    }
}

interface ILove{
    void love(int a);
}

Summary:

  • lambda expressions can only be reduced to one line if there is only one line of code. If there are multiple lines, they are wrapped in code blocks.
  • The premise of lambda expression is that the interface is functional.
  • Parameter types can also be removed from multiple parameters. To remove them, remove them all and add parentheses.

6. Thread stop

1. Thread status


2. Method of thread stop
  • It is recommended that threads stop normally - > utilization times, and dead loops are not recommended
  • It is recommended to use flag bit - > set a flag bit
  • Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK
public class TestStop implements Runnable{
    //1. Set a flag bit
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while(flag){
            System.out.println("run...Thread"+ i++);
        }
    }

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

    public static void main(String[] args) {
        TestStop stop = new TestStop();
        new Thread(stop).start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if(i==900){
                //Call the stop method to switch the flag bit and stop the thread
                stop.stop();
                System.out.println("The thread stopped");
            }
        }
    }
}

7. Thread sleep()

  • Sleep (time) specifies the number of milliseconds that the current thread is blocked;
  • Exception InterruptedException exists in sleep;
  • After the sleep time reaches, the thread enters the ready state;
  • sleep can simulate network delay, countdown, etc;
  • Each object has a lock, and sleep does not release the lock.
Example 1: analog delay: TestThread
 Simulating the role of network delay: amplifying the occurrence of the problem
//Analog countdown
public class TestSleep1 {

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

    public static void tenDown() throws InterruptedException {
        int num = 10;
        while(true){
            Thread.sleep(1000);
            System.out.println(num--);
            if(num<=0){
                break;
            }
        }
    }
}
//Print system current time
public class TestSleep2 {
    public static void main(String[] args) {
        Date startTime = new Date(System.currentTimeMillis());  //Get the current system time
        while(true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());  //Update current time
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

8. Thread comity - yield()

  • Comity thread, which allows the currently executing thread to pause without blocking;
  • Change the thread from running state to ready state;
  • Let the CPU reschedule. Comity is not necessarily successful. It depends on the CPU mood.
public class TestYield {

    public static void main(String[] args) {
        MyYield myYield = new MyYield();

        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();

    }
}

class MyYield implements Runnable{

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

9. Thread enforcement - join()

  • join merge threads. After this thread is executed, other threads will be executed, and other threads will be blocked;
  • Imagine jumping in line
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; 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);

        //Main thread
        for (int i = 0; i < 1000; i++) {
            if(i == 200){
                thread.start();
                thread.join(); //Jump in line
            }
            System.out.println("main"+i);

        }
    }
}

10. Observe thread status

public class TestState {

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

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

        //Start after observation
        thread.start();   //Start thread
        state = thread.getState();
        System.out.println(state);
        System.out.println();   //Run

        while(state != Thread.State.TERMINATED){  //As long as the thread does not stop, it always outputs the state
            Thread.sleep(100);
            state = thread.getState();    //Update thread status
            System.out.println(state);   //Output status

            //thread.start();    An error is reported because the dead thread can no longer be started
        }
    }
}

11. Thread priority

  • Java provides a thread scheduler to monitor all threads that enter the ready state after startup. The thread scheduler determines which thread should be scheduled to execute according to priority.
  • The priority of threads is expressed in numbers, ranging from 1 to 10
    • Thread.MIN_PRIORITY = 1;
    • Thread.MAX_PRIORITY = 10;
    • Thread.NORM_PRIORITY = 5;
  • Use the following methods to change or obtain priority
    • getPriority.setPriority(int xxx)
public class TestPriority {
    public static void main(String[] args) {
        //Default priority of main thread
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();

        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);
        Thread t6 = new Thread(myPriority);

        //Set priority before starting
        t1.start();

        t2.setPriority(1);
        t2.start();

        t3.setPriority(4);
        t3.start();

        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();

//        t5.setPriority(-1);   //Exception in thread "main" java.lang.IllegalArgumentException
//        t5.start();
//
//        t6.setPriority(11);   //Exception in thread "main" java.lang.IllegalArgumentException
//        t6.start();

    }

}

class MyPriority implements  Runnable{

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

Conclusion: low priority only means that the probability of obtaining scheduling is low, not that it will not be called if the priority is low. It all depends on the CPU scheduling.

12. Daemon thread

  • Threads are divided into user threads and daemon threads
  • The virtual machine must ensure that the user thread is completed (e.g., main)
  • The virtual machine does not have to wait for the daemon thread to finish executing (for example, recording operation logs in the background, monitoring memory, garbage collection...)
//God protects you
public class TestDaemon {

    public static void main(String[] args) {
        God god = new God();
        You2 you = new You2();

        Thread thread = new Thread(god);
        thread.setDaemon(true);   //The default false indicates that it is a user thread, and normal threads are user threads

        thread.start();  //God daemon thread start

        new Thread(you).start();   //Your user thread starts
    }
}

//lord
class God implements Runnable{

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

//you
class You2 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("You live happily all your life");
        }
        System.out.println("=====GoodBye World!======");
    }
}

13. Thread synchronization mechanism

Concurrency: the same object is operated by multiple threads at the same time (for example, tens of thousands of people rob tickets at the same time)

When dealing with multithreading, multiple threads access the same object(Concurrent),And some threads also want to modify this object. In this case, thread synchronization is required.
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 be used, and then use the next thread.

Conditions for thread synchronization: queue + lock

19. Three major unsafe cases

[1. Buy tickets]

//Thread unsafe, negative number
public class UnsafeBuyTicket  implements  Runnable{
    //Number of votes
    private int ticketNums = 10;
    boolean flag = true;  //External stop method

    @Override
    public void run() {
        while(flag){
           buy();
        }
    }
    
    public void  buy(){
        //Judge whether there are tickets
        if(ticketNums<=0){
            flag = false;
            return;
        }
        //Analog delay
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticketNums-- +"ticket");
    }

    public static void main(String[] args) {
        UnsafeBuyTicket ticket = new UnsafeBuyTicket();

        new Thread(ticket,"Xiao Ming").start();
        new Thread(ticket,"teacher").start();
        new Thread(ticket,"cattle").start();
    }

}

[2. Unsafe bank]

public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(100,"fund");
        Drawing you = new Drawing(account,50,"you");
        Drawing wo = new Drawing(account,100,"wo");

        you.start();
        wo.start();
    }
}

//account
class  Account{
    int money; //balance
    String name;  //Card name

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

//Bank: simulated withdrawal
class Drawing extends Thread{
    Account account;  //account
    int drawingMoney;  //How much did you withdraw
    int nowMoney;   //How much money do you have now

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

    //Withdraw money
    @Override
    public void run() {
        //Judge whether there is money
        if(account.money-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 = balance - withdrawn money
        account.money = account.money - drawingMoney;
        //Money in hand
        nowMoney = nowMoney + drawingMoney;

        System.out.println(account.name+"The balance is:"+account.money);
        System.out.println(this.getName()+"Money in hand:"+nowMoney);
    }
}

[3. Unsafe collection]

public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        //Thread.sleep(500);
        System.out.println(list.size());
    }
}
//Output: 9999

20. Synchronization method and synchronization method block

◆Because we can pass private Keyword to ensure that data objects can only be accessed by methods,Therefore, we only need to propose a set of mechanism for the method,This mechanism is synchronized keyword,It includes two uses:synchronized Methods and synchronized block

  Synchronization method: public synchronized void method(int args) }

◆synchronized Method to control access to the object,Each object corresponds to a lock,each synchronized Methods must obtain the lock of the object calling the method in order to execute,Otherwise, the thread will block, and once the method is executed,Just monopolize the lock,The lock is not released until the method returns,Only later blocked threads can obtain this lock,Continue.
defect:If a large method is declared as synchronized Will affect efficiency

Only the contents that need to be modified in the method need to be locked, otherwise resources will be wasted

◆Synchronization block: synchronized (Obj){}
◆Obj It's called a synchronization monitor
◆Obj Can be any object,However, shared resources are recommended as synchronization monitors
◆You do not need to specify a synchronization monitor in the synchronization method,Because the synchronization monitor of the synchronization method is this , It's the object itself,Or class [Explanation in reflection]
◆Synchronization monitor execution
1.First thread access,Lock synchronization monitor,Execute the code.
2.Second thread access,Synchronization monitor found locked,cannot access.
3.First thread access completed,Unlock sync monitor
4.The second thread accesses and finds that the synchronization monitor has no lock,Then lock and access

Modify three unsafe cases as safe:

[1. Buy tickets]

public class UnsafeBuyTicket  implements  Runnable{
    //Number of votes
    private int ticketNums = 10;
    boolean flag = true;  //External stop method

    @Override
    public void run() {
        while(flag){
            buy();
        }
    }

    //synchronized synchronization method, this object
    public  synchronized void  buy(){
        //Judge whether there are tickets
        if(ticketNums<=0){
            flag = false;
            return;
        }
        //Analog delay
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticketNums-- +"ticket");
    }

    public static void main(String[] args) {
        UnsafeBuyTicket ticket = new UnsafeBuyTicket();

        new Thread(ticket,"Xiao Ming").start();
        new Thread(ticket,"teacher").start();
        new Thread(ticket,"cattle").start();
    }
}

[2. Withdrawal]

public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(200,"fund");
        Drawing you = new Drawing(account,50,"you");
        Drawing wo = new Drawing(account,100,"wo");

        you.start();
        wo.start();
    }
}

//account
class  Account{
    int money; //balance
    String name;  //Card name

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

//Bank: simulated withdrawal
class Drawing extends Thread{
    Account account;  //account
    int drawingMoney;  //How much did you withdraw
    int nowMoney;   //How much money do you have now

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

    //Withdraw money
    @Override
    public void run() {

        synchronized (account){
            //Judge whether there is money
            if(account.money-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 = balance - withdrawn money
            account.money = account.money - drawingMoney;
            //Money in hand
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.name+"The balance is:"+account.money);
            System.out.println(this.getName()+"Money in hand:"+nowMoney);

        }
    }
}

[3. Set]

public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(500);
        System.out.println(list.size());
    }
}
//Output: 10000

[4. Test JUC safety set]

public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> copy = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{

                copy.add(Thread.currentThread().getName());


            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(copy.size());
    }
}
//Output: 10000

21. Deadlock

1. Definitions
Multiple threads each occupy one-Some shared resources,And wait for the resources occupied by other threads to run,As a result, two or more threads are waiting for each other to release resources,All stop execution. When a synchronization block has "locks of more than two objects" at the same time,The problem of "deadlock" may occur.
//Deadlock: multiple threads hold each other's required resources
public class DeadLock {

    public static void main(String[] args) {
        Makeup m1 = new Makeup(0,"Xiao Hei");
        Makeup m2 = new Makeup(1,"Xiaobai");

        m1.start();
        m2.start();
    }
}

//Lipstick
class Lipstick{

}

//mirror
class Mirror{

}

//Make up
class Makeup extends Thread{

    //There is only one resource needed. Use static to ensure that there is only one
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    int choice;   //choice
    String name;   //People who use cosmetics

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

    @Override
    public void run() {
        //Make up
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //Makeup, holding each other's locks, is to get each other's resources
    private  void makeup() throws InterruptedException {
        if(choice ==0){
            synchronized (lipstick){  //Get lipstick lock
                System.out.println(this.name+"Get lipstick lock");
                Thread.sleep(1000);
            }
            synchronized (mirror){  //I want to get the lock of the mirror in a second
                System.out.println(this.name+"Get the lock of the mirror");
            }
        }else{
            synchronized (mirror){  //Get the lock of the mirror
                System.out.println(this.name+"Get the lock of the mirror");
                Thread.sleep(2000);
            }
            synchronized (lipstick) {  //I want to get the lock of lipstick in two seconds
                System.out.println(this.name + "Get lipstick lock");
            }
        }
    }
}

Solution: take out the synchronization code block and don't two people hold a lock at the same time.

private  void makeup() throws InterruptedException {
    if(choice ==0){
        synchronized (lipstick){  //Get lipstick lock
            System.out.println(this.name+"Get lipstick lock");
            Thread.sleep(1000);
        }
        synchronized (mirror){  //I want to get the lock of the mirror in a second
            System.out.println(this.name+"Get the lock of the mirror");
        }
    }else{
        synchronized (mirror){  //Get the lock of the mirror
            System.out.println(this.name+"Get the lock of the mirror");
            Thread.sleep(2000);
        }
        synchronized (lipstick) {  //I want to get the lock of lipstick in two seconds
            System.out.println(this.name + "Get lipstick lock");
        }
    }
}
2. Deadlock avoidance method
  • Four necessary conditions for deadlock generation:
    • Mutex condition: a resource can only be used by one process at a time.
    • Request and hold condition: when a process is blocked by requesting resources, it will hold on to the obtained resources.
    • Conditions of non deprivation: the resources obtained by the process cannot be forcibly deprived before they are used up.
    • Circular waiting condition: a circular waiting resource relationship is formed between several processes.

Just destroy one of them. Deadlock can be avoided.

22.LOCK

◆from JDK 5.0 Start, Java Provides a more powerful thread synchronization mechanism_-Synchronization is achieved by explicitly defining the synchronization lock object. Use of synchronization lock Lock Object acts as;
◆java.util.concurrent.locks.Lock Interface is a tool that controls multiple threads to access shared resources. Locks provide exclusive access to shared resources, with only one thread pair at a time Lock Object is locked, and the thread should obtain the lock before accessing the shared resource Lock object
◆ReentrantLock Class implements Lock ,It has and synchronized The same concurrency and memory semantics are commonly used in thread safety control ReentrantLock,You can explicitly add and release locks.

Examples of safe ticket buying:

class TestLock2 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(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "-->Got the second" + ticketNums-- + "ticket");
                } else {
                    break;
                }
            }finally {
                //Unlock
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new TestLock2(),"Yellow Cattle").start();
    }
}

Note: if you need to throw an exception, unlock() needs to be written in the finally {} block

synchronized vs Lock
Lock Is an explicit lock(Manually open and close the lock. Don't forget to close the lock) synchronized It is an implicit lock, which is automatically released out of the scope
◆Lock Only code block locks, synchronized There are code block locks and method locks
◆use Lock Lock, JVM It will take less time to schedule threads for better performance. And it has better scalability(Provide more subclasses)
◆Priority order:
Lock >Synchronous code block(It has entered the method body and allocated corresponding resources) >Synchronization method(Outside the method body)

23. Thread collaboration producer consumer model

1. Thread communication

(1) Application scenario: producer and consumer issues
◆ it is assumed that only - pieces of products can be stored in the warehouse, the producer will put the produced products into the warehouse, and the consumer will take away the products in the warehouse for consumption
◆ if there is no product in the warehouse, the producer will put the product into the warehouse, otherwise stop production and wait until the product in the warehouse is taken away by the consumer
◆ if there is a product in the warehouse, the consumer can take the product away for consumption, otherwise stop consumption and wait until the product is put in the warehouse again

(2) Analysis:
This is a thread synchronization problem. Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other
◆ for producers, inform consumers to wait before producing products, and inform consumers to consume immediately after producing products
◆ for consumers, after consumption, inform producers that consumption has ended and new products need to be produced for consumption
◆ in producer consumer issues, synchronized is not enough
◆ synchronized can prevent concurrent updating of the same shared resource and realize synchronization
◆ synchronized cannot be used to realize message transmission (Communication) between different threads

(3) Solution:
Concurrent collaboration model "producer / consumer model" – >

a. Pipe program method
◆ producer: module responsible for production data (may be method, object, thread, process);
◆ consumers: modules responsible for processing data (may be methods, objects, threads, processes);
◆ buffer zone: consumers cannot directly use the producer's data. There is a "buffer zone" between them“
The producer puts the produced data into the buffer, and the consumer takes out the data from the buffer

public class GuanCheng {
    public static void main(String[] args) {
        SynContainer synContainer = new SynContainer();
        new Productor(synContainer).start();
        new Consumer(synContainer).start();
    }

}
//producer
class Productor extends  Thread{
    SynContainer container;

    public Productor(SynContainer container) {
        this.container = container;
    }
    //production
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            container.push(new Chicken(i));
            System.out.println("Produced the second"+i+"Chicken");
        }
    }
}
//consumer
class Consumer extends Thread{
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }

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

}
//product
class Chicken{
    int id;  //Product number
    public Chicken(int id){
        this.id = id;
    }
}
//buffer
class SynContainer{
    //A container size is required
    Chicken[] chickens = new Chicken[20];
    //Container counter
    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 and waiting
            try {
                this.wait();
            } catch (InterruptedException 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 the producer to produce
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //Take out the product if you can consume it
        count--;
        Chicken chicken = chickens[count];

        //The producer can be informed of consumption
        this.notifyAll();

        return chicken;
    }
}

b. Signal lamp method

public class xinhao {

    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("Happy base camp");
            }else{
                this.tv.play("make progress every day");
            }
        }
    }
}
//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 actor performs and the audience waits for T
    //The audience watched and the actors waited for F
    String voice;   //perform
    boolean flag = true;

    //perform
    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();   //Notification wake up
        this.voice = voice;
        this.flag = !this.flag;
    }

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

}

24. Thread pool

Use thread pool
◆background:Resources that are often created and destroyed and used heavily, such as threads in concurrency, have a great impact on performance.
◆thinking: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, which is similar to public transportation in life.
◆benefit:
Improve response speed(Reduced time to create new threads)
Reduce resource consumption(Reuse threads in the thread pool without creating them every time)
Easy thread management
corePoolSize: Size of core pool
maximumPoolSize:Maximum number of threads
keepAliveTime: When a thread has no task, how long will it last at most and then terminate

◆JDK 5.0 Thread pool correlation is provided API: ExecutorService and Executors
◆ExecutorService: Real thread pool interface. Common subclasses ThreadPoolExecutor
void execute(Runnable command) :Perform tasks/command,No return value, generally used to execute Runnable
Future submit(Callable task):Perform tasks,There is a return value, which is generally used to execute Callable
void shutdown() :Close connection pool
◆Executors: Tool class and thread pool factory class, which are used to create and return different types of thread pools
public class TestPool {

    public static void main(String[] args) {
        //1. Create service and thread pool
        ExecutorService service = Executors.newFixedThreadPool(10);  //The parameter is the thread pool size

        //implement
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

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

}

class MyThread implements Runnable{

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


Keywords: Java Multithreading

Added by bobbfwed on Sat, 02 Oct 2021 23:38:24 +0300