Thread sharing and collaboration in concurrent programming

For more advanced video learning of Android architecture, please click: https://space.bilibili.com/47...
This article will discuss thread sharing and collaboration from the following aspects:

[interpretation of CPU core number, thread number and time slice rotation mechanism of basic concepts]
[sharing between threads]
[collaboration between threads]

I. Basic Concepts

Number of CPU cores and threads
The relationship between the two: the number of cpu cores and threads is 1:1. For example, an 8-core cpu supports 8 threads running at the same time. But after intel introduced hyper threading technology, the relationship between cpu and thread number became 1:2. In addition, there is no thread limitation in the development process, which is due to the algorithm of the cpu time slice rotation mechanism (RR scheduling). What is the rotation mechanism of cpu time slice

CPU time slice rotation mechanism
Meaning: the cpu assigns a "time period" to each process, which is called the "time slice" of this process. This time slice is the allowed running time of this process. If the time slice of this process ends, the operating system will deprive the cpu assigned to this process and assign it to another process. If the process is blocked before the end of the time slice, or the process runs out, the cpu will switch. The cpu switching between two processes is called "context switching". Context switching takes about 5000-20000 (5-20 MS, which is determined by the operating system) clock cycles, although we usually don't feel it. So in the development process, we should pay attention to the impact of context switching (switching between two processes) on our program performance.

2. Sharing between threads

synchronized built-in lock
The thread starts to run and has its own stack space. Just like a script, it executes step by step according to the established code until it is terminated. However, if each running thread only runs in isolation, it has little or no value. If multiple threads can cooperate with each other to complete the work, including data sharing and collaborative processing. This will bring great value.

Java supports multiple threads to access an object or its member variables at the same time. The keyword synchronized can be used in the form of a method or a synchronization block. It mainly ensures that multiple threads can only have one thread in a method or a synchronization block at the same time. It ensures the visibility and exclusiveness of thread access to variables, also known as the built-in locking mechanism.
volatile keyword
volatile ensures the visibility when different threads operate on this variable, that is, one thread modifies the value of a variable, which is immediately visible to other threads.

private volatile static boolean ready;
private static int number;
Without volatile, the sub thread cannot perceive that the main thread has modified the value of ready, so it will not exit the loop. With volatile, the sub thread can perceive that the main thread has modified the value of ready, and exit the loop quickly. However, volatile cannot guarantee thread safety when data is written in multiple threads at the same time. See code:
thread-platformsrccomchjthreadcapt01volatilesNotSafe.java
volatile is the most suitable scenario: one thread writes and multiple threads read.
Thread private variable ThreadLocal

+ get() Get each thread's own threadLocals A copy of the local variable in.
+ set() Set each thread's own threadLocals Copy of thread local variables in.
ThreadLocal There is an inner class ThreadLocalMap:

                    public T get() {
                    Thread t = Thread.currentThread();
                    //According to the current thread, return a ThreadLocalMap. Click getMap
                    ThreadLocalMap map = getMap(t);
                    if (map != null) {
                        ThreadLocalMap.Entry e = map.getEntry(this);
                        if (e != null) {
                            @SuppressWarnings("unchecked")
                            T result = (T)e.value;
                            return result;
                        }
                    }
                    return setInitialValue();
                }
                
                 //Click the getMap(t) method to find that the returned internal variable is ThreadLocal.ThreadLocalMap of the current thread
                    ThreadLocalMap getMap(Thread t) {
                    return t.threadLocals;
                }
                //It can be seen from this that when the get method of ThreadLocal is called, it actually returns the variables in the threadlocals (type is ThreadLocal.ThreadLocalMap) of the current thread. The call to the set method is similar.
                
                //An example of a usage scenario
                /**
             * ThreadLocal Usage scenario: store the database connection object in ThreadLocal
             * Advantage: reduces the need to create a Connection every time a Connection is acquired
             * Disadvantage: because each thread will store a local variable, the problem of memory consumption needs to be considered.
             * @author luke Lin
             *
             */
            public class ConnectionThreadLocal {
                private final static String DB_URL = "jdbc:mysql://localhost:3306:test";
                private static ThreadLocal<Connection> connectionHolder  = new ThreadLocal<Connection>(){
                    protected Connection initialValue() {
                        try {
                            return DriverManager.getConnection(DB_URL);
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        return null;
                    };
                };
                
                /**
                 * Get connection
                 * @return
                 */
                public Connection getConnection(){
                    return connectionHolder.get();
                }
                
                /**
                 * Release connection
                 */
                public void releaseConnection(){
                    connectionHolder.remove();
                }
            }
     
                //Suggestions to solve the problem of memory leak caused by weak reference in ThreadLocal
                + statement ThreadLoal When using private static Modification
                + In thread, if the local variable is no longer used, even if the remove()

III. cooperation among threads

wait() notify() notifyAll()

        //1.3.1 notification waiting wake-up mode
            //1) waiting party
                //Get lock of object
                //In the loop, judge whether the conditions are met. If not, execute wait and block wait.
                //If the conditions are met, jump out of the loop and execute your own business code
            
            //2) notification party
                //Get lock of object
                //Change condition
                //Perform notifyAll notification, etc
        //1.3.2 
            //wait notify notifyAll are built-in methods of objects
            //wait notify notifyAll needs to be executed within synchronized, otherwise it will be wrong.
            //Executing the wait method leaves the lock held by the object until two things happen: 1. Wake up by notify/notifyAll. 2. Wait timeout
        //1.3.3 for example, wait (int millis) and notifyAll are used to realize a simple timeout connection of line city pool
/*
 * Connection pool, support connection timeout.
 * When the connection is over a certain period of time, timeout processing is performed.
 */
public class DBPool2 {
    LinkedList<Connection> pools;
    //Initializes a new city pool of the specified size
    public DBPool2 (int poolSize) {
        if(poolSize > 0){
            pools =  new LinkedList<Connection>(); 
            for(int i=0;i < poolSize; i++){
                pools.addLast(SqlConnectImpl.fetchConnection());
            }
        }
    }
    
    
    /**
     * Get connection
     * @param remain Wait timeout
     * @return
     * @throws InterruptedException 
     */
    public Connection fetchConn(long millis) throws InterruptedException {
        // Timeout must be greater than 0, otherwise, throw a game
        synchronized (pools) {
            if (millis<0) {
                while(pools.isEmpty()) {
                    pools.wait();
                }
                return pools.removeFirst();
            }else {
                // Timeout time
                long timeout = System.currentTimeMillis() + millis;
                long remain = millis;
                // If the current pool's connection is empty, wait for timeout. If the timeout time has not been returned, return null.
                while (pools.isEmpty() && remain > 0) {
                    try {
                        pools.wait(remain);
                        remain = timeout - System.currentTimeMillis();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Connection result = null;
                if (!pools.isEmpty()) {
                    result = pools.removeFirst();
                }
                return result;
            }
        }

    }
    
    /**
     * Release connection
     */
    public void releaseConn(Connection con){
        if(null != con){
            synchronized (pools) {
                pools.addLast(con);
                pools.notifyAll();
            }
        }
    }
}

sleep() yield()
join()
Interview point: thread A executes the join method of county B, so thread A must wait until thread B executes before thread A can continue its work.
The effect of wait() notify() yield() sleep() on locks
Interview point:
Thread execution yield(), the thread gives up cpu execution time, and competes with other threads for cup execution opportunities at the same time, but if the lock held is not released.
The thread executes sleep(), and the thread gives up the cpu execution time. Before sleep() wakes up, it does not compete for the cpu execution time, but if the lock held is not released.
The lock must be held before calling notify, and calling the notify method itself will not release the lock.
The wait() method must hold the lock before calling. After calling the wait method, the lock will be released. When the wait method returns, the thread holds the lock again.
For more advanced video learning of Android architecture, please click:[ https://space.bilibili.com/47...]
Reference resources: https://blog.csdn.net/m0_3766...
https://www.cnblogs.com/codet...
https://blog.csdn.net/aimashi...

Tags: Android Java Database JDBC

Posted on Mon, 04 Nov 2019 10:39:24 -0500 by Shad