Detailed explanation and case analysis of common methods of multithreading

Time:2022-5-22

Multithreaded programming

Multithreading is to apply the principle of this concurrent execution mechanism in the operating system to a program. A program is divided into several subtasks. Multiple subtasks are executed concurrently, and each task is a thread. This is a multithreaded program.

1. Using threads, you can put the tasks in the program that occupy a long time in the background.

2. The user interface can be more attractive. For example, if the user clicks a button to trigger the processing of some events, a progress bar can pop up to display the processing progress.

3. The program may run faster.

4. In the implementation of some waiting tasks, such as user input, file reading and writing, network sending and receiving data, threads are more useful. In this case, some precious resources can be released, such as memory occupation.

5. Multithreading technology also plays an important role in IOS software development.

Thread common

synchronized 						// Synchronous lock
volatile   							// so
CountDownLatch 						// Counter
ReenTrantLock 						// Reentry lock (fair lock)
TimeUnit 							// Cooperation time example (timeunit. Seconds. Sleep (1) sleep for one second)
Semaphore
lockInterruptibly 					// Interrupt lock
lock 								// Lock
unlock 								// Unlock
tryLock 								// Judge whether there is a lock and return Boolean
wait 								// Thread waiting
sleep 								// Thread sleep
notify  								// Thread wakeup

Method of multithreading implementation

There are three kinds in total. The commonly used ones are inheriting thread class and implementing runnable interface

There is another way to implement the callable interface. The following mainly introduces the two commonly used interfaces

Because inheritance can only be implemented by single inheritance and multiple inheritance, it is recommended to use the implementation interface

Inherit thread class

1. Create a new class and inherit thread class

public class Test1 {
    public static void main(String[] args) {
        T1 t = new T1();
        t.start();
    }
}

class T1 extends Thread {
    @Override
    public void run() {

    }
}

2. Anonymous inner class

public class Test1 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                
            }
        }).start();
    }
}

3. Lambda expression

public class Test1 {
    public static void main(String[] args) {
        new Thread(() -> {
        }).start();
    }
}

Implement runnable interface

1. Create a new class implementation interface

public class Test1 {
    public static void main(String[] args) {
        T1 t =new T1();
        Thread tt =new Thread(t);
        tt.start();
    }
}

class T1 implements Runnable{
    @Override
    public void run() {
        
    }
}

2. Anonymous inner class

public class Test1 {
    public static void main(String[] args) {
        var t = new Runnable() {
            @Override
            public void run() {
                
            }
        };
        Thread tt =new Thread(t);
        tt.start();
    }
}

Common methods of multithreading

The following is the multithreading state. Be sure to remember!!!!

image-20210828105128329

Set and get the priority of threads

The priority range (1-10) is 5 by default

//Thread.MAX_PRIORITY 10
//Thread.MIN_PRIORITY 1
//Thread.NORM_PRIORITY 5
Thread. currentThread(). Setpriority (thread. Max_priority) // set the thread priority
Thread. currentThread(). Getpriority() // get the thread priority

Set and get the name of the thread

Thread. currentThread(). Setname ("T1") // set the thread name
Thread. currentThread(). Getname() // get the thread name

Thread sleep

Sleep will not release the synchronization lock. It will be explained in detail later. The usage method will be introduced first

Thread. Sleep (1000) // let the thread sleep for 1 second timeunit SECONDS. Sleep (1) // let the thread sleep for one second

Thread waiting

Wait will release the synchronization lock and wait, which will be described later

wait()//

Multithreading tool class

Timer TimerTask

timer

Public class threadtimer {public static void main (string [] args) throws parseexception {timer timer timer = new timer(); simpledateformat SDF = new simpledateformat ("yyyy MM DD HH: mm: SS"); date d = sdf.parse ("2021-8-24 20:14:30"); // set the specified time timer.schedule (New timertask() {@ override public void run() {system.out.printf( "%1$tF %1$tT %n", System. currentTimeMillis());            }        },  d, 3000);// D is the start time of execution. It will not be executed until D. 3000 is to execute every 3 seconds after starting execution. Timer T2 = new timer(); t2. Schedule (New timertask() {@ override public void run() {timer. Cancel(); // revocation of the first timer T2. Cancel(); // T2 timer revocation}}, 20 * 1000)// Start execution in 20 seconds}}

TimeUnit

java. util. A class under the concurrent package represents the time period of a given unit granularity

image-20210828111608399

CountDownLatch

Public class thread9 {public static void main (string [] args) {new thread (test:: add, "T1"). Start(); // the first parameter here is a lambda expression, indicating the use of the add method. The second parameter is to set the thread name new thread (() - > {while (! Test. Count()); system. Out. Println ("there are five");}, "t2"). start();    }} Class test {static volatile list = new ArrayList < > (); private static countdownlatch latch = new countdownlatch (1); // the parameter here indicates how many times to open public static void add() {string TN = thread. Currentthread(). Getname(); // get the thread name system.out.println (TN + "thread start"); while (true) {try {timeunit. Seconds. Sleep (1); // sleep for one second} catch (interruptedexception E) {e.printstacktrace();} list. add("item:" + (list.size() + 1)); Add an element system to the list every time out. printf("%s = %s %n", list.size(), list. get(list.size() - 1));            // Open if (list. Size() = = 5) {latch. Countdown();}}} once when the list has 5 elements// Public static Boolean count() {Boolean f = false; try {latch. Await(); // the thread will not execute f = true until the latch is opened catch (InterruptedException e) {            e.printStackTrace();        }         return f;    }}

synchronized

Synchronous lock (exclusive lock)

Reentrantlock is often compared with synchronized for analysis. Let’s compare it first and then analyze it bit by bit.

(1) Synchronized is an exclusive lock. The process of locking and unlocking is automatic and easy to operate, but not flexible enough. Reentrantlock is also an exclusive lock. The process of locking and unlocking needs to be carried out manually. It is not easy to operate, but it is very flexible.

(2) Synchronized can re-enter, because locking and unlocking are carried out automatically, so you don’t have to worry about whether to release the lock at last; Reentrantlock can also be re entered, but locking and unlocking need to be done manually, and the number of times should be the same, otherwise other threads cannot obtain the lock.

(3) Synchronized does not respond to interrupts. A thread waits until it can get a lock; Reentrantlock can be interrupted accordingly.

Reentrantlock doesn’t seem to be much better than the synchronized keyword. Let’s take a look at what synchronized doesn’t have. One of the most important is that reentrantlock can also realize the fair lock mechanism. What is a fair lock? That is, the thread that waits the longest on the lock will get the right to use the lock. The popular understanding is that who has the longest queue time will execute to obtain the lock first.

Synchronization method format (lock object is this)

Modifier synchronized return value type method name (method parameter) {method body;}

Synchronous static method format (lock object is. Class)

Modifier static synchronized return value type method name (method parameter) {method body;}

Synchronization code block (the object of the lock is determined by yourself)

Synchronized (object) {method body}

Here is a ticket to use the synchronization lock

If the thread is not safe without locking, dirty reading and wrong reading will occur when buying tickets

There will be the same sum of votes, and the number of votes will be negative

public class Thread6 {    public static void main(String[] args) throws InterruptedException {        Thicket t = new Thicket();        Thread t1 = new Thread(t, "t1");        Thread t2 = new Thread(t, "t2");        Thread t3 = new Thread(t, "t3");        t1.start();        t2.start();        t3.start();    }} class Thicket implements Runnable {    int i = 100;    @Override    public void run() {        while (true) {            synchronized (this) {                if (i == 0) {                    break;                }                 System. out. println(Thread.currentThread(). Getname() + "got the first" + I + "ticket"); i--;            }        }    }}

ReentrantLock

Reentry lock (fair lock): each thread will execute once before executing

Public class test1 {lock lock = new reentrantlock (true); // set to true fair lock, inefficient but fair void m() {for (int i = 0; I < = 20; I + +) {lock. Lock(); // lock system.out.println (thread. Currentthread(). Getname()); try {timeunit. Seconds. Sleep (1);} catch (Exception e) {                e.printStackTrace();            }             lock. unlock();// Unlock}} public static void main (string [] args) {var t = new test1(); new thread (T:: m, "T1"). Start(); new thread (T:: m, "T2"). Start(); new thread (T:: m, "T3"). Start(); new thread (T:: m, "T4"). Start();}}
/*** @ author sulishijian * @ date 2021 / 8 / 26-14:14 * @ since 16 * / public class test1 {static lock lock = new reentrantlock(); public static void main (string [] args) {var t = new thread (test1:: Test); t.start(); t.interrupt(); // break lock} static void test() {try {lock. Lockinterrupt(); for (int i = 0; I < 10; I + +) {                System.out.println(i);            }        }  catch (InterruptedException e) {            System.out.println("......");        }  Finally {if (lock. Trylock()) {lock. Unlock(); system. Out. Println ("thread 2 is interrupted");}}}}

wait sleep

1 sleep() implements thread blocking. We call it “thread sleep”. The way is to wait for timeout
2. The wait () method implements thread blocking. We call it “thread waiting”. Like the sleep () method, we pass in “sleep time” as a parameter and “wake up” when the time comes;
Do not pass in the time, conduct an “indefinite wait”, and only “wake up” through the notify() method.
3 sleep() releases the CPU Execution Authority, but does not release the synchronization lock;
4 wait() releases the CPU Execution Authority and the synchronization lock, so that other threads can use the synchronization control block or method.

There are two cases. The first is the pipe process method, and the second is the signal lamp method to deeply understand wait

package demo1;/** * @ Author sulishijian * @ date 2021 / 8 / 20-19:24 * @ since 16 * / public class thread4 {public static void main (string [] args) {panel panel = new panel(); new thread (() - > {for (int i = 0; I < 100; I + +) {system.out.printf ("produced% d chicken% n", I); panel.push (new chicken (I));}}) start();         New thread (() - > {for (int i = 0; I < 100; I + +) {system. Out. Printf ("consumed% d chicken% n", panel. Pop(). ID);}}) start();    }}// Define a common class class chicken {int ID; public chicken (int ID) {this. Id = ID;}}// Container class panel {volatile chicken [] chickens = new chicken [10]; // defines an array of objects to store data. Volatile is used to make the array data visible to both threads. Int count = 0; public synchronized void push (chicken chicken chicken) {// if there are ten, wait for consumption if (count = = chickens. Length) {try {this. Wait() ;// Release the lock to wait for wake-up} catch (interruptedexception E) {e.printstacktrace();}} chickens[count] = chicken;// Put the produced things into the array count + +// The counter is incremented by this notify();// If there are no ten, wake up the consumer to consume} public synchronized chicken pop() {// if the number is 0, wait for production if (count = = 0) {try {this. Wait(); // wait} catch (interruptedexception E) {e.printstacktrace();}} count--;// Counter minus one chicken = chickens [count]// Take something out of this notify();// Wake up the producer to produce return chicken;}}
package demo1;/** * @ Author sulishijian * @ date 2021 / 8 / 26-20:17 * @ since 16 * / public class thread14 {public static void main (string [] args) {TV TV TV = new tv(); new thread (() - > {for (int i = 0; I < 20; I + +) {if (I% 2 = = 0) {tv.play ("navigation king");} Else {TV. Play ("Douluo continent");}}} start();         new Thread(() -> {            for (int i = 0; i < 20; i++) {                tv.watch();            }        }). start();    }} Class TV {// if there is no program, the flag is false to start the performance. If there is a program, it is true to start watching volatile boolean flag = false; string voice; public synchronized void play (string voice){ 	// If true, there is a program waiting for the audience to watch if (flag) {try {this. Wait(); // release the lock to wait for wake-up} catch (interruptedexception E) {e.printstacktrace();}} System. out. Println ("performed:" + voice); this. notifyAll();// At this time, it is false to wake up the audience to watch this voice = voice;// Show this flag = ! this. flag;// False becomes true} public synchronized void watch() {// if false, there is no program waiting for actors to perform if (! Flag) {try {this. Wait(); // release the lock to wait for wake-up} catch (interruptedexception E) {e.printstacktrace();}} System. out. Println ("watched:" + voice); this. notifyAll();// Wake up the actors to perform this flag = ! this. flag;// Change true to false}}

join

ThreadTest t1=new ThreadTest(“A”);
ThreadTest t2=new ThreadTest(“B”);
t1.start();
t1.join();
t2.start();
Execute thread T1 first, and then thread T2.

ThreadTest t1=new ThreadTest(“A”);
ThreadTest t2=new ThreadTest(“B”);
ThreadTest t3=new ThreadTest(“C”);
t1.start();
t2.start();
t1.join();
t3.start();
T1 thread and T2 thread execute alternately. When T1 thread executes, T3 thread starts. The execution process has nothing to do with T2

It can be seen from many experiments that the main thread is in T1 Stop at the join () method and wait for thread a to finish executing before executing T3 Start(), however, does not affect the execution of the B thread. Therefore, it can be concluded that the T. join () method will only make the main thread enter the waiting pool and wait for the T thread to wake up after execution. It does not affect other threads running at the same time.

PS: in the source code of the join, only the wait method will be called, and notify will not be called at the end. This is because the thread will automatically call its notifyAll method during die to release all resources and locks.

Realize three threads, run and output A1 B2 C3 A4 B5 C6

/** * @author sulishijian * @date 2021/8/26-14:14 * @since 16 */public class Test1 {    AtomicInteger num = new AtomicInteger(0);    synchronized void work() {        try {            TimeUnit.SECONDS.sleep(1);        } catch (Exception e) {            e.printStackTrace();        }        String n = Thread.currentThread().getName();        System.out.printf("%s%d ", n, num.incrementAndGet());        if ("C".equals(n)) {            System.out.println();        }    }    public static void main(String[] args) throws InterruptedException {        var t = new Test1();        while (true) {            var t1 = new Thread(t::work, "A");            t1.start();            t1.join();            var t2 = new Thread(t::work, "B");            t2.start();            t2.join();            var t3 = new Thread(t::work, "C");            t3.start();            t3.join();        }    }}

interrupt

/** * @author sulishijian * @date 2021/8/26-16:44 * @since 16 */public class Thread12 {    static boolean flag = false;    public static void main(String[] args) {        var t = new Thread(Thread12::work);        t.start();        try {            TimeUnit.SECONDS.sleep(5);            t.interrupt();        }  catch (InterruptedException e) {            e.printStackTrace();        }    }     Public static void work() {thread t = thread. Currentthread(); string TT = t.getname(); system.out.printf ('% s' thread started% n', TT); system.out.println (t.isinterrupted()); while (! T.isinterrupted()) {try {timeunit. Seconds. Sleep (1);} catch (InterruptedException e) {                break;            }             System. out. println(".......");        }         System. out. println(t.isInterrupted());         System. out. Printf ('% s' thread ended% n', TT);}}

Multithreaded instance

Thread safety

Conditions for safety problems

It is a multithreaded environment with shared data and multiple statements operating on shared data

resolvent

Thread synchronization (queuing mechanism)

Variables with thread safety issues

//Local variables will never have thread safety problems (local variables will never be shared in the stack) instance variables static variables

deadlock

For example, there are threads a and B. the first thread writes lock B in lock a, and the second thread writes lock a in lock B

A takes the a lock to get the b lock, B takes the b lock to get the a lock, and both threads occupy the lock. If you want the other party’s lock, it will freeze all the time, and then form a deadlock

It is recommended to sleep in the lock for one second, otherwise a may run too fast and take the full lock below

/** * @author sulishijian * @date 2021/8/26-14:14 * @since 16 */public class Test1 {    static Object A = new Object();    static Object B = new Object();    public static void TA() {        synchronized (A) {            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("A");            synchronized (B) {                System.out.println("B");            }        }    }    public static void TB() {        synchronized (B) {            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("B");            synchronized (A) {                System.out.println("A");            }        }    }    public static void main(String[] args) {        new Thread(Test1::TA).start();        new Thread(Test1::TB).start();    }}

Find the expression of + – and 100 between 123456789. If one thread finds the result, immediately tell the others to stop

/*** @ author sulishijian * @ date 2021 / 8 / 25-15:47 * @ since 16 * / public class thread10 {static volatile set = new HashSet < > (); static void op() {system.out.println (thread. Currentthread(). Getname() + "starting"); string [] o = new string [] {"", "+", "-"}; Random rand = new Random();         Pattern p = Pattern. compile("-?\\d+");         while (set.size() !=  10) {            StringBuffer sbf = new StringBuffer("1");            for (int i = 2; i <= 9; i++) {                sbf.append(String.format("%s%d", o[rand.nextInt(o.length)], i));            }             String s = sbf. toString();             Matcher m = p.matcher(s);             List list = new ArrayList<>();             while (m.find()) {                list.add(Integer.parseInt(m.group()));            }             int sum = list. stream(). reduce(0, Integer::sum);             if (sum == 100 && !set.contains(s)) {                set.add(s);                System.out.println(Thread.currentThread().getName() + ":" + s);            }        }    }         public static void main(String[] args) {        for (int i = 0; i < 5; i++) {            new Thread(Thread10::op, "i" + i).start();        }    }}

Add 10 elements to the container, and thread 2 monitors the number of elements. When the number reaches 5, thread 2 gives a prompt and ends

/*** @ author sulishijian * @ date 2021 / 8 / 25-9:46 * @ since 16 * / public class thread9 {public static void main (string [] args) {new thread (test:: add, "T1"). Start(); new thread (() - > {while (! Test. Count()); system. Out. Println ("five already");}, "t2"). start();    }} Class test {static volatile list = new ArrayList < > (); private static countdownlatch latch = new countdownlatch (3); public static void add() {string TN = thread. Currentthread(). Getname(); system. Out. Println (TN + "thread start"); while (true) {try {timeunit. Seconds. Sleep (1);} catch (InterruptedException e) {                e.printStackTrace();            }             list. add("item:" + (list.size() + 1));             System. out. printf("%s = %s %n", list.size(), list. get(list.size() - 1));             if (list.size() % 5 == 0) {                latch.countDown();            }        }    }     public static boolean count() {        boolean f = false;        try {            latch.await();            f = true;        }  catch (InterruptedException e) {            e.printStackTrace();        }         return f;    }}

Recommended Today

JS generate guid method

JS generate guid method https://blog.csdn.net/Alive_tree/article/details/87942348 Globally unique identification(GUID) is an algorithm generatedBinaryCount Reg128 bitsNumber ofidentifier , GUID is mainly used in networks or systems with multiple nodes and computers. Ideally, any computational geometry computer cluster will not generate two identical guids, and the total number of guids is2^128In theory, it is difficult to make two […]