当前位置:网站首页>ThreadLocal not yet? Come and have a look!

ThreadLocal not yet? Come and have a look!

2022-06-10 04:31:00 little-peter

ThreadLocal Designed to address concurrency , The problem of threads sharing variables , Due to over design , Such as weak references and hash collisions , It is difficult to understand and high cost . besides , A little careless use will also cause dirty data and memory leakage , Shared variable update and so on . But even so ,ThreadLocal It still has its own applicable scenarios , And irreplaceable value , For example, the following two usage scenarios , except ThreadLocal outside , There is really no suitable alternative .

  Use scenarios 1: The local variable

  Let's take multithreading to format time as an example , To demonstrate ThreadLocal The value and function of , When we format time in multiple threads , It's usually done this way .

  1. When there are two threads for time formatting , We can write this way :
import java.text.SimpleDateFormat;

import java.util.Date;


public class Test {

    public static void main(String[] args) throws InterruptedException {

        //  Create and start the thread 1

        Thread t1 = new Thread(new Runnable() {

            @Override

            public void run() {

                //  Get the time object 

                Date date = new Date(1 * 1000);

                //  Perform time formatting 

                formatAndPrint(date);

            }

        });

        t1.start();

        //  Create and start the thread 2

        Thread t2 = new Thread(new Runnable() {

            @Override

            public void run() {

                //  Get the time object 

                Date date = new Date(2 * 1000);

                //  Perform time formatting 

                formatAndPrint(date);

            }

        });

        t2.start();

    }


    /**

     *  Format and print the results 

     * @param date  Time object 

     */

    private static void formatAndPrint(Date date) {

        //  Format time object 

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");

        //  Perform formatting 

        String result = simpleDateFormat.format(date);

        //  Print final results 

        System.out.println(" Time :" + result);

    }

}

The running result of the above program is :

The above code creates a small number of threads , So we can create a private object for each thread  SimpleDateFormat To format the time .

2.10 Threads to format time

When there is 10 When a thread performs time formatting , We can use for Loop creates multiple threads to perform time formatting , The specific code is as follows :

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

public class Test {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            //  Create thread 
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    //  Get the time object 
                    Date date = new Date(finalI * 1000);
                    //  Perform time formatting 
                    formatAndPrint(date);
                }
            });
            //  Start thread 
            thread.start();
        }
    }
    /**
     *  Format and print the time 
     * @param date  Time object 
     */
    private static void formatAndPrint(Date date) {
        //  Format time object 
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");
        //  Perform formatting 
        String result = simpleDateFormat.format(date);
        //  Print final results 
        System.out.println(" Time :" + result);
    }
}

The execution result of the above procedure is :

As can be seen from the above results , Although the number of threads created at this time and SimpleDateFormat It's not a small number , But the program still works .

3.1000 Thread formatting

When we change the number of threads from 10 A into 1000 When it's time , We can't just use for Loop to create 1000 A thread way to solve the problem , Because the frequent creation and destruction of threads will cause a lot of system overhead and excessive thread contention CPU The question of resources . So after some thinking , We decided to use the thread pool to perform this 1000 Tasks , Because thread pool can reuse thread resources , No need to create and destroy threads frequently , You can also control the number of threads in the thread pool to avoid the problems caused by too many threads CPU Performance problems caused by excessive resource contention and frequent thread switching , And we can put SimpleDateFormat Promoted to a global variable , So as to avoid creating a new one every time SimpleDateFormat The problem of , So we wrote this code :

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class App {
    //  Time formatting objects 
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");

    public static void main(String[] args) throws InterruptedException {
        //  Create a thread pool to perform tasks 
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 60,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000));
        for (int i = 0; i < 1000; i++) {
            int finalI = i;
            //  Perform tasks 
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    //  Get the time object 
                    Date date = new Date(finalI * 1000);
                    //  Perform time formatting 
                    formatAndPrint(date);
                }
            });
        }
        //  The thread pool closes after the task is executed 
        threadPool.shutdown();
    }

    /**
     *  Format and print the time 
     * @param date  Time object 
     */
    private static void formatAndPrint(Date date) {
        //  Perform formatting 
        String result = simpleDateFormat.format(date);
        //  Print final results 
        System.out.println(" Time :" + result);
    }
}

The execution result of the above procedure is :

The above results show that our code is thread unsafe .

Thread safety problem : In multithreaded execution , The execution result of the program is not consistent with the expected result .

  • Why do these problems occur ?

In order to find the problem , Let's try to see SimpleDateFormat in format Method source code to check the problem ,format Source code is as follows :

private StringBuffer format(Date date, StringBuffer toAppendTo,

                                FieldDelegate delegate) {

    //  Notice this line of code 

    calendar.setTime(date);

  From the above source code can be seen , In execution SimpleDateFormat.format When the method is used , Will use calendar.setTime Method to convert the input time , So let's imagine a scene like this :

  1. Threads 1 Yes calendar.setTime(date) Method , The time entered by the user is converted into the time required for later formatting ;
  2. Threads 1 Suspend execution , Threads 2 obtain CPU The time slice starts to execute ;
  3. Threads 2 Yes calendar.setTime(date) Method , The time has been modified ;
  4. Threads 2 Suspend execution , Threads 1 obtain CPU Time slice continues , Because the thread 1 And thread 2 Using the same object , And time has been threaded 2 Revised , So when the thread 1 There will be thread safety problems when the execution continues .
  • Solving thread safety problems : Lock

When thread safety issues arise , The first solution we came up with was to lock , The specific implementation code is as follows :

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.concurrent.LinkedBlockingQueue;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;


public class App {

    //  Time formatting objects 

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");


    public static void main(String[] args) throws InterruptedException {

        //  Create a thread pool to perform tasks 

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 60,

                TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000));

        for (int i = 0; i < 1000; i++) {

            int finalI = i;

            //  Perform tasks 

            threadPool.execute(new Runnable() {

                @Override

                public void run() {

                    //  Get the time object 

                    Date date = new Date(finalI * 1000);

                    //  Perform time formatting 

                    formatAndPrint(date);

                }

            });

        }

        //  The thread pool closes after the task is executed 

        threadPool.shutdown();

    }


    /**

     *  Format and print the time 

     * @param date  Time object 

     */

    private static void formatAndPrint(Date date) {

        //  Perform formatting 

        String result = null;

        //  Lock 

        synchronized (App.class) {

            result = simpleDateFormat.format(date);

        }

        //  Print final results 

        System.out.println(" Time :" + result);

    }

}

The disadvantages of locking

Although locking can solve the problem of thread safety , But it also brings new problems , When the program is locked , All threads have to queue up to perform some business , In this way, the efficiency of the program will be reduced .

Can we solve the problem of thread safety , A solution that can improve the execution speed of the program ?

yes , we have , This is the time ThreadLocal We're going to play .

Here's the good food :https://blog.csdn.net/qq_49425839/article/details/117389318

Refer to teacher Wang Lei's words

 

原网站

版权声明
本文为[little-peter]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206091240103792.html