Concurrent Programming threads sharing and collaboration (a)

Learn more Android architecture advanced video please click: https://space.bilibili.com/474380680
This article from the following elements to illustrate threads sharing and collaboration:

[Based on the concept of CPU cores, the number of threads, round-robin mechanism Interpretation]
[shared between threads]
[collaboration between threads]

First, the basic concept

CPU core count, the number of threads
relationship between the two: the number of threads and cores cpu is 1: 1 relationship, such as an 8-core cpu, it supports 8 threads to run simultaneously. But after the introduction of Hyper-Threading technology intel, cpu relationship with the number of threads becomes 1: 2. Also did not feel the limit of threads in the development process, it is because the role of cpu round-robin algorithm mechanism (RR scheduling). What is the round-robin mechanism cpu see below 1.2.

CPU time slice rotation mechanism
meaning is: cpu to each process assigned a "period of time", this time period is called the process a "time slice", this time slice is the time to allow the process to run, if the time when the process of end of the segment, the operating system will be allocated to this process cpu deprivation, assigned to another process. If the process is blocked in the case of a time slice is not yet over, or finish the process, cpu will be switched. cpu switching between two processes is called "context switching" context switching takes time, it takes about 5,000 to 20,000 (5 ms to 20 ms, the time it takes is determined by the operating system) clock cycles, Although we usually do not feel. So during the development process should pay attention to the influence of context switches (switching between the two processes) to our program performance.

Second, shared between threads

Built-synchronized lock
thread is running with its own stack space, like a script as a step performed in accordance with established codes step until terminated. However, each running thread, if it is run in isolation only, then no little value, or worth very little, if multiple threads can cooperate with each other to complete the work, including the sharing of data among collaborative deal with things. This will bring tremendous value.

Java support multiple threads access the member variables of an object or objects, keywords can be modified synchronized method or in the form of sync blocks to use, it is mainly to ensure that multiple threads at the same time, only one thread in a method or sync block, it ensures visibility and exclusive threads of variable access, also known as the built-in locking mechanism.
The volatile keyword
volatile to ensure visibility when different threads to this variable operation, that is a thread modifies the value of a variable, this new value to other thread is immediately visible.

volatile static boolean ready Private;
Private static int Number The;
when no volatile, can not perceive the child thread the main thread changes the value ready so as not to exit the loop, and added a volatile, the child thread the main thread can modify the perception of the ready value, quickly exit the loop. But the volatile security thread can not guarantee when the data is written simultaneously in multiple threads, see the code:
the Thread-Platform \ src \ COM \ CHJ \ the Thread \ capt01 \ Volatiles \ NotSafe.java
volatile most suitable scene: a thread to write, and more read threads.
Thread private variables ThreadLocal


+ get() 获取每个线程自己的threadLocals中的本地变量副本。
+ set() 设置每个线程自己的threadLocals中的线程本地变量副本。
ThreadLocal有一个内部类ThreadLocalMap:

                    public T get() {
                    Thread t = Thread.currentThread();
                    //根据当前的线程返回一个ThreadLocalMap.点进去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();
                }

                 //点击去getMap(t)方法发现其实返回的是当前线程t的一个内部变量ThreadLocal.ThreadLocalMap
                    ThreadLocalMap getMap(Thread t) {
                    return t.threadLocals;
                }
                //由此可以知道,当调用ThreadLocal的get方法是,其实返回的是当前线程的threadLocals(类型是ThreadLocal.ThreadLocalMap)中的变量。调用set方法也类似。

                //举例一个使用场景
                /**
             * ThreadLocal使用场景:把数据库连接对象存放在ThreadLocal当中.
             * 优点:减少了每次获取Connection需要创建Connection
             * 缺点:因为每个线程本地会存放一份变量,需要考虑内存的消耗问题。
             * @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;
                    };
                };

                /**
                 * 获取连接
                 * @return
                 */
                public Connection getConnection(){
                    return connectionHolder.get();
                }

                /**
                 * 释放连接
                 */
                public void releaseConnection(){
                    connectionHolder.remove();
                }
            }

                //解决ThreadLocal中弱引用导致内存泄露的问题的建议
                + 声明ThreadLoal时,使用private static修饰
                + 线程中如果本地变量不再使用,即使使用remove()

# 三、 线程间的协作

**wait() notify() notifyAll()**

        //1.3.1通知等候唤醒模式
            //1)等候方
                获取对象的锁
                在循环中判断是否满足条件,如果不满足条件,执行wait,阻塞等待。
                如果满足条件跳出循环,执行自己的业务代码

            //2)通知方
                获取对象的锁
                更改条件
                执行notifyAll通知等等待方
        //1.3.2 
            //wait notify notifyAll都是对象内置的方法
            //wait notify notifyAll 都需要加synchronized内被执行,否则会抱错。
            //执行wait方法是,会让出对象持有的锁,直到以下2个情况发生:1。被notify/notifyAll唤醒。2。wait超时
        //1.3.3 举例使用wait(int millis),notifyAll实现一个简单的线城池超时连接
/*
 * 连接池,支持连接超时。
 * 当连接超过一定时间后,做超时处理。
 */
public class DBPool2 {
    LinkedList<Connection> pools;
    //初始化一个指定大小的新城池
    public DBPool2 (int poolSize) {
        if(poolSize > 0){
            pools =  new LinkedList<Connection>(); 
            for(int i=0;i < poolSize; i++){
                pools.addLast(SqlConnectImpl.fetchConnection());
            }
        }
    }

    /**
     * 获取连接
     * @param remain 等待超时时间
     * @return
     * @throws InterruptedException 
     */
    public Connection fetchConn(long millis) throws InterruptedException {
        // 超时时间必须大于0,否则抛一场
        synchronized (pools) {
            if (millis<0) {
                while(pools.isEmpty()) {
                    pools.wait();
                }
                return pools.removeFirst();
            }else {
                // 超时时间
                long timeout = System.currentTimeMillis() + millis;
                long remain = millis;
                // 如果当前pools的连接为空,则等待timeout,如果timeout时间还没有返回,则返回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;
            }
        }

    }

    /**
     * 释放连接
     */
    public void releaseConn(Connection con){
        if(null != con){
            synchronized (pools) {
                pools.addLast(con);
                pools.notifyAll();
            }
        }
    }
}

**sleep() yield()**
**join()**
面试点:线程A执行了县城B的join方法,那么线程A必须等到线程B执行以后,线程A才会继续自己的工作。
**wait() notify() yield() sleep()对锁的影响**
面试点:
线程执行yield(),线程让出cpu执行时间,和其他线程同时竞争cup执行机会,但如果持有的锁不释放。
线程执行sleep(),线程让出cpu执行时间,在sleep()醒来前都不竞争cpu执行时间,但如果持有的锁不释放。
notify调用前必须持有锁,调用notify方法本身不会释放锁。
wait()方法调用前必须持有锁,调用了wait方法之后,锁就会被释放。当wait方法返回的时候,线程会重新持有锁。
更多Android架构进阶视频学习请点击:[https://space.bilibili.com/474380680]
参考:https://blog.csdn.net/m0_37661458/article/details/90692419
https://www.cnblogs.com/codetree/p/10188638.html
https://blog.csdn.net/aimashi620/article/details/82017700

Guess you like

Origin blog.51cto.com/14591958/2447755