並行プログラミングのスレッドが共有とコラボレーション(A)

より多くのAndroidのアーキテクチャ高度なビデオを学びクリックしてください:https://space.bilibili.com/474380680
次の要素からこの記事では、共有とコラボレーションのスレッドを説明するために:

[CPUコアの概念、スレッドの数に基づいて、ラウンドロビン機構の解釈]
[スレッド間で共有]
[スレッド間の連携]

まず、基本的な概念

CPUコア数、スレッド数
両者の関係:スレッドとコアCPUの数は、1:1人の関係は、8コアCPUと、それは同時に実行する8つのスレッドをサポート。2:しかし、ハイパースレッディング・テクノロジーインテルの導入後、スレッドの数とCPUの関係は1になります。また、開発プロセス内のスレッドの限界を感じていなかった、それがあるため、CPUラウンドロビンアルゴリズムメカニズム(RRスケジューリング)の役割。ラウンドロビン機構CPUが1.2未満に何を見ています。

CPUタイムスライス回転機構の
意味は次のとおりです。各プロセスにCPUが「一定の期間」が割り当てられ、この期間は、「タイムスライス」プロセスと呼ばれ、このタイムスライスは、プロセスの実行を許可する時間である時間かのときのプロセスセグメントの終了、オペレーティングシステムは、このプロセスCPU欠乏に割り当てられた他のプロセスに割り当てられます。プロセスがタイムスライスの場合にブロックされている場合はまだ終わっていない、またはプロセスを終了し、CPUが切り替えられます。2つのプロセス間のCPU切り替えが呼び出され、「コンテキストの切り替え」コンテキスト切り替えは、それが約5,000〜20,000(20ミリ秒〜5ミリ秒、それに要する時間は、オペレーティングシステムによって決定される)クロックサイクルを要し、時間がかかり、我々は通常、感じることはありませんが。だから、開発プロセスの間に我々のプログラムのパフォーマンスに(2つのプロセス間の切り替え)コンテキストスイッチの影響に注意を払う必要があります。

第二に、スレッド間で共有

内蔵の同期ロック
解除されるまで確立コードに従って行うステップはステップとしてスレッドはスクリプトのように、独自のスタック空間で実行されています。しかし、各実行中のスレッド、それは単独でのみ、その後、何のほとんど価値、または実行されていない場合は価値が複数のスレッドが物事との共同契約の間でデータの共有など、作業を完了するためにお互いに協力できるかどうか、非常に少ないです。これは非常に大きな価値をもたらすでしょう。

Javaは、複数のスレッドがキーワードを使用する同期メソッドまたはシンクブロックの形で変更することができ、または複数のオブジェクトのメンバ変数にアクセスし、それは同時に、複数のスレッドを確実にするために主にサポートする方法で唯一のスレッドまたはシンクブロックは、それが可視とも内蔵ロック機構として知られている変数へのアクセスの排他的なスレッドを、確実にします。
揮発性キーワード
別のスレッドがこの変数の操作に、そのスレッドは、変数の値を変更するときの視認性を確保するために揮発性は、他のスレッドにこの新しい値が直ちに表示されています。

揮発プライベート準備静的ブール;
プライベート静的int型の数;
とき無揮発性、子供がメインスレッドをスレッド知覚できないループを終了しないように準備ができて値を変更し、揮発性を追加し、子供はメインスレッドが準備完了の認識を変更することができますスレッド値は、すぐにループを終了します。:しかし、データが複数のスレッドで同時に書き込まれると揮発性、セキュリティスレッドが保証することはできません、コード参照の
スレッドプラットフォーム\ SRC \ COM \ CHJ \スレッド\ capt01 \揮発分\ NotSafe.java
揮発最も適したシーン:書き込むためのスレッド、および多くをスレッドを読んで。
プライベート変数をスレッドの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

おすすめ

転載: blog.51cto.com/14591958/2447755