多線程

多線程

1.區分併發與並行

併發:單核CPU在某一個時間段,不斷的交互運行,宏觀並行,微觀併發。

並行:多核CPU,在同一時刻,同時運行多個應用程序

2.區分進程與線程

進程:系統運行的某一個應用

線程:進程中處理的多個任務,依賴進程存在,一個進程可以有多個線程

3.線程的創建

創建線程的四種方式:繼承Thread類,實現Reunable接口,實現Callable接口,使用線程池Exceutor。

1.實現Runnable接口
	實現run方法 Runnable對象:任務對象  創建線程對象:new Thread(任務對象)
2.繼承Thread類
	覆蓋run方法
3.創建線程池(避免重複的創建和銷燬線程,可以讓一個線程執行多個任務)
ExecutorService es = Executors.newFixedThreadPool(線程sum);(固定數量線程池)
ExecutorService es = Executors.newCachedThreadPool();(可變線程池)
es.submit(任務對象); 
es.shutdown();關閉線程池
4.實現Callable接口(有返回值,能拋異常)
ExecutorService es = Executors.newCachedThreadPool();
實現call方法 Callable對象:任務對象  創建線程對象:es.submit(任務對象);
接收返回值並跑異常:Future f1 = es.submit(任務對象);

4.線程的組成

CPU時間片:操作系統會給每個線程分配執行時間

運行數據:

​ 堆空間(共享):存儲線程需使用的對象,多個線程可以共享堆種的對象

​ 棧空間(獨立):存儲線程需要使用的局部變量,每個線程都擁有獨立的棧

線程的邏輯代碼

5.Thread的基本狀態

初始狀態:線程對象被創建,只在堆中開闢內存

就緒狀態:調用start()之後,進入就緒狀態,等待系統選中,並分配時間片

運行狀態:獲得時間片之後,進入運行狀態,如果時間片到期,回到就緒狀態

終止狀態:主線程main()或獨立線程run()結束,進入終止狀態並釋放擁有的時間片

等待狀態:

​ 有限期等待

​ 1.調用Thread.sleep()進入有限期等待狀態,到期後線程進入就緒狀態,等待系統分配時間片,不會釋放鎖標記

​ 無限期等待

​ 2.調用線程.join()進入無限期等待,

阻塞狀態:線程沒有鎖標記進入阻塞狀態 ,等待鎖標記

6.Thread中的方法

sleep:限時等待 休眠

yield:放棄CPU 回到就緒狀態

setDaemon(true):設置線程爲守護線程,所有非守護線程都結束時,進程就會結束

join():當前線程進入等待狀態,直到線程終止,纔會恢復執行

7.線程安全問題

當多線程共同訪問同一個對象(臨界資源)的時候,如果破壞了不可分割的操作(原子操作),就可能發生數據不一致

每個Java對象都有一個互斥鎖標記,用來分配給線程

synchronized(o) { } 對 o 加鎖的同步代碼塊,只有拿到o的鎖標記的線程,才能進入對o枷鎖的同步代碼塊

synchronized 方法修飾符 對this加鎖的同步代碼塊 只有拿到o的鎖標記的線程,才能調用o的同步方法

8.死鎖問題

死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱爲死鎖進程。

避免死鎖: 加鎖順序(線程按照一定的順序加鎖),鎖時限(線程嘗試獲取鎖的時候加上一定的時限,超過時限則放棄對該鎖的請求,並釋放自己佔有的鎖),死鎖檢測,避免嵌套鎖

9.線程通信(等待通知機制)

object.wait():必須出現在對object加鎖的同步代碼塊 線程會釋放鎖標記,進入等待狀態

object.notify/notifyAll():必須出現在對object加鎖的同步代碼塊,從等待狀態中釋放一個/全部線程

10.Lock接口

創建Lock對象

Lock lock = new ReentrantLock();

上鎖:調用lock.lock()方法

解鎖:調用lock.unlock()方法

獲得隊列對象

Condition c1 = lock.newCondition();

c1.await(): 進入等待隊列

c1.signalAll():喚醒等待的線程

11.jdk1.5線程安全的集合

用ArrayList實現一個高併發讀寫分離的集合

package com.baizhi.controller;

import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by 拂曉 on 2019/9/15:18:01
 */
public class MyList extends ArrayList {
	//讀寫鎖  寫鎖未分配時,讀鎖可以反覆分配 讀寫分離
    ReadWriteLock rwl = new ReentrantReadWriteLock();

    Lock r1 = rwl.readLock();//共享鎖
    Lock w1 = rwl.writeLock();

    @Override
    public int size() {
       try {
           r1.lock();
           return super.size();

       }finally {
           r1.unlock();
       }

    }

    @Override
    public Object get(int index) {
        try {
            r1.lock();
            return super.get(index);    
        }
        finally {
            r1.unlock();
        }
        
    }

    @Override
    public boolean add(Object o) {
        
        try {
            w1.lock();
            return super.add(o);

        }finally {
            w1.unlock();
        }
        
    }

    @Override
    public Object remove(int index) {
        try {

            w1.lock();
            return super.remove(index);
        }finally {
            w1.unlock();
        }
    }

    @Override
    public void clear() {
        
        try {
            w1.lock();
            super.clear();
        }finally {
            w1.unlock();
        }
    }
}

以下線程安全的集合類,都來自Java併發包java.util.concurrent

CopyOnWriteArrayList : 利用複製數組的方式實現數組元素的修改 寫效率低,讀效率高 (適用於讀操作多於寫操作的場景),同樣的還有CopyOnWriteArraySet類

ConcurrentHashMap:實現方式是分段鎖,將散列表分割成16段,每段加鎖,各段互不影響,讀寫效率高

ConcurrentLinkedQueue:線程安全的隊列,用鏈表實現的隊列,實現方式無鎖算法CAS(比較交換算法),效率很高

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章