Java線程安全

(一)線程安全
(1)如何解決多線程的安全問題?
校驗一個多線程程序是否有安全問題的隱患的前提條件:
1)當前程序是否是多線程環境
2)是否有共享數據
3)是否有多條語句對共享數據進行操作

看當前案例是否有多線程的安全問題:
1)是否是多線程環境 是
2)是否有共享數據 是
3)是否有多條語句對共享數據進行操作 是

現在就需要解決安全問題:
1)多線程環境 不能解決
2)對共享數據進行優化 不能解決
3)解決將多條語句對共享數據這一環進行解決

(2)解決方案:就是將多條語句對共享數據操作的代碼,用一個代碼包起來---->代碼--->同步代碼塊

    格式:
        synchronized(鎖對象){
                針對多條語句對共享數據操作代碼;
        }

    鎖對象:肯定一個對象,隨便創建一個對象(匿名對象) 
        給剛纔的這個程序加入了同步代碼塊,但是鎖對象使用的匿名對象(每一個線程進來都有自己的鎖),還是沒有解決!
      鎖對象:每一個線程最總使用的鎖對象,只能是同一把鎖
        注意:
    鎖對象:一定要同一個鎖(每個線程只能使用同一把鎖)
    鎖對象:任何的Java類(引用類型)

(3)Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。此實現允許更靈活的結構
可以使用Lock鎖進行具體的鎖定操作類 提供了具體的實現類:ReentrantLock
加鎖並且去釋放鎖
Lock解決了多線程安全問題,但是還是有些問題:
1)執行效率低
2)會產生死鎖
死鎖:兩個或兩個以上的線程,在執行的過程中出現互相等待的情況,就叫做死鎖!
(4)Java的等待喚醒機制
分析:
Student類: 資源類
SetThread:設置學生的數據(生產者線程)
GetThread:獲取(輸出)學生數據(消費者線程)
StudentDemo:測試類

  • 需求:SetThread線程給學生對象進行賦值,在通過消費者線程輸出該學生數據,設計這樣一個程序!

  • null----0 按照剛纔的思路,發現有一個問題,的數據null---0

  • 解決方案:線程死鎖的注意事項:要保證生產者線程和消費者線程針對同一個對象進行操作的!
    在外部創建一個學生對象,將這個學生對象通過構造方法傳入到各個線程中

    需求:消費者線程,和生產者線程加入循環操作,改進

    又有問題:
    1)同一個人的姓名和年齡出現多次
    2)姓名和年齡不符
    爲什麼?
    1)CPU的一點點時間片,在某一個時間點,足夠它執行很多次
    2)線程具有隨機性

  • 解決方案:
    1)是否是多線程環境 是
    2)是否有功共享數據 是
    3)是否有多條語句對共享數據進行操作 有
  • 同步機制(同步代碼塊/同步方法)
  • 開發中,使用synchronized(Lock鎖也可以)同步代碼塊將多條語句對共享數據的操作包起來!
  • 繼續改進:
    上面的代碼改進之後,雖然加入了同步機制,但是打印一打印一大片同樣,讓數據依次打印數據!

  • 如何解決:
    就使用的是Java的等待喚醒機制
    Java線程安全
    (二)線程組
    (1)線程組:
    程組表示一個線程的集合。此外,線程組也可以包含其他線程組

    • public ThreadGroup(String name)構造一個新線程組
    • 線程名.getThreadGroup().getName() 直接獲取線程組名稱

    (2)線程池
    線程池:多個線程執行完畢,它會重新回到線程池中,等待被利用,不會變成垃圾!
    和線程池有關的類
    類 Executors: 一種工廠類

    方法:
        和線程池的創建有關係
        public static ExecutorService newFixedThreadPool(int nThreads)
        創建一個可重用固定線程數的線程池

    ExecutorService:可以執行異步任務
    創建一個線程池,執行接口中的方法
    提交:Future<?> submit(Runnable task)
    <T> Future<T> submit(Callable<T> task)提交一個返回值的任務用於執行,返回一個表示任務的未決結果的
    (3)Future
    Future:接口
    Future 表示異步計算的結果

        線程池調用完畢可以關閉的
        void shutdown():關閉之前,會提交剛纔的任務
    
    (4)多線程實現方式第三種:
  • 前提:自定義類實現Callable接口
  • 1)創建線程池對象: Executors 裏面的那個方法,返回的是ExecutorsService
  • 2) 然後調用ExecutorsService裏面的提交任務的方法:
  • <T> Future<T> submit(Callable<T> task)提交一個返回值的任務用於執行
  • 3)關閉線程池
    (三)簡單工廠模式
    (1)設計原則
    設計原則:
    單一職責原則:
    低耦合,高內聚
    耦合性:類與類之間產生的關係
    低耦合:讓類與類之間的關係不復雜
    內聚:執行一個件事情(功能)的能力
    高內聚:一個類能夠完成的事情,不要使用多個類一起來執行!

    數據庫
    對某個數據進行增刪改查(查詢很重要的)
    定一個接口:
    增();
    刪();
    改();
    查();
    實現類:
    業務邏輯層:
    增(){
    增加xxx聯繫人/商品列表
    }

    2:開閉原則
    核心思想是:一個對象對擴展開放,對修改關閉

    開發好一個程序(項目),儘量不要修改原有代碼
    類和類之間假設有關係
    更改一個類的功能,其他類已需要更改(增加代碼的代碼的書寫量)
    SVN(版本控制)/git

設計模式:
創建型模式 對象的創建

    (2)簡單工廠模式--->靜態工廠方法模式 
設計一個工廠類:
    工廠類提供一些靜態方法,間接的去創建具體的對象
  • 優點:
  • 不需要在創建具體類的對象,而是把創建的工作交給了工廠類來創建!
  • 弊端:如果有新的對象增加,或者某些對象的創建方式不同,就需要不斷的修改工廠類,不利於後期的維護
    (3)工廠方法模式
    提供一個抽象類(抽象工廠)還需要提供一個接口(工廠接口),每一個具體的類都有對應的工廠類(實現工廠接口)
    具體對象的創建工作由繼承抽象工廠的具體類實現

  • 優點:
    客戶端不需要在負責對象的創建(不需顯示創建具體對象),從而明確了各個類的職責,
    如果有新的對象增加,只需要增加一個具體的類和具體的工廠類即可,不影響已有的代碼,後期維護容易,增強了系統的擴展性
  • 弊端:
    書寫代碼量大了!
    (4)設計模式之單例模式
    單例模式核心思想:某些類的對象在創建的時候 ,在系統內存始終只有一個對象!
    單例模式分類:
    1)餓漢式 2)懶漢式(類似於多線程環境..)
    1)餓漢式:

      在加載那個類的時候,對象的創建工作就已經完成了!
  • 兩種分類在設計上幾乎一樣:
  • 1)定義個類,將該類的無參構造方法私有化
  • 2)在該類的成員位置創建該類對象 並且一定要私有化,防止外界更改這個對象
  • 3)在該類中提供靜態成員方法(返回值就是創建的那個對象),能被當前類直接調用,static修飾
    2)懶漢式:
    符合單例模式核心思想
    1)自定義一個類,將無參構造私有化
    2)在成員位置聲明變量
    3)提供公共靜態功能,在裏面判斷的創建該類對象,返回該類對象

  • 如果是開發中,那麼就使用餓漢式(餓漢式它不會出現問題的單例模式)
  • 如果是面試中,那麼使用懶漢式(因爲他是可能出現問題的一種單例模式)
  • 懶漢式(延遲加載 -->懶加載)
  • 可能會出現問題
  • ---> 多線程的問題
  • --->校驗多線程安全問題的標準
  • 1)是否是多線程環境
  • 2)是否有共享數據
  • 3)是否有多條語句對共享數據進行操作 (使用同步機制進行操作)
    (四)計算機網絡
    (1)概念:計算機網絡:
    多臺計算機通過網絡協議,實現網絡資源共享和信息傳遞!

http://localhost:端口號 (80)www.baidu.com

username:admin
password:%AE%.... MD5算法 加密很難解密

網絡通信三要素

1)ip地址
2)端口號
3)應該有一些規則(協議UDP/TCP)

舉例:
    我想和高圓圓聊天...
    1)找到她,才能和她說話------>IP地址
    2)假設找她了,怎麼說呢?
        對着她耳朵說話------->port端口號
    3)要對她:i love you 
            假設不懂英文,----->定義規則(協議)

IP地址:
192.168.10.1 (通過8421碼將可以由0,1組成的一些數據)
點分十進制法:十進制.十進制.十進制.十進制 書寫簡單

    11000000.0000100....

    Ip地址的分類:

        IP地址的組成
        IP地址 = 網絡號碼+主機地址

        A類IP地址:第一段號碼爲網絡號碼,剩下的三段號碼爲本地計算機的號碼
                一般情況:國防部/大的國部門
        B類IP地址:前二段號碼爲網絡號碼,剩下的二段號碼爲本地計算機的號碼
                    一般情況:大學裏面的多媒體教室
        C類IP地址:前三段號碼爲網絡號碼,剩下的一段號碼爲本地計算機的號碼
                    私人地址

A類 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互聯網上不使用,而被用在局域網絡中的地址) (2)127.X.X.X是保留地址,用做循環測試用的。
B類 128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
C類 192.0.0.1---223.255.255.254 192.168.X.X是私有地址
D類 224.0.0.1---239.255.255.254
E類 240.0.0.1---247.255.255.254

127.0.0.1--->表示本地計算機的迴環地址
dos
ipconfig
ping ip地址 是否能通信

        聲吶系統(二戰)  

端口號:0~65535有效端口號
0-1024屬於保留端口

mysql:3306 

協議:
UDP協議 --->UDP編程
不需要建立連接通道的
數據大小有限制
不可靠連接
執行效率高
TCP協議 ---->TCP編程
需要建立連接通道
數據大小無限制
可靠連接
執行效率低

打電話:看成TCP協議  建立連接通道
發短信:UDP協議   不需要建立連接通道
(2)InetAddress:類表示互聯網協議 (IP) 地址
  • 如果一個類中沒有構造方法,沒有字段,只有成員方法?有什麼特徵
  • 1)應該有一些靜態功能(Math類,Arrays,Collections...)
  • 2)可能符合一種單例模式(餓漢/懶漢)
  • 3)該類中的某些靜態成員方法的返回值是該類本身
  • 舉例
  • public class Demo{
  • public static Demo getDemo(){
  • new Demo() ;
  • }
  • }
  • 常用方法:
  • public static InetAddress getByName(String host)
    throws UnknownHostException在給定主機名的情況下確定主機的 IP 地址。
    參數:
    主機名可以是機器名(如 "java.sun.com"),也可以是其 IP 地址的文本表示形式
    (3)Udp編程
  • 1)不需要建立連接通道
  • 2)數據大小有限制
  • 3)不可靠連接---->傳輸速度快!
  • 發送端的開發步驟:
  • 1)創建發送端的Socket對象
  • 2)創建數據,並打包
  • 3)調用當前發送端Socket對象中的發送的方法
  • 4)關閉資源Udp編程的接收端 開發步驟:
  • 1)創建Socket對象
  • 2)創建一個數據報包(接收容器)
  • 3)調用Socket對象中的接收的方法
  • 4)解析實際傳遞的數據
  • 5)將解析的數據(ip,數據)展示在控制檯上
  • 6)關閉資源
  • 注意:
  • 接收端不要運行多次,會出現異常:
  • java.net.BindException: Address already in use: Cannot bind
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章