Java第五週總結

Java第五週

lambda表達式

思想 “說重點”

lambda表達式的核心即在於說重點
以線程代碼爲例,他需要的是什麼?最核心的東西是什麼?
就是run方法!!!
runnable接口中重寫實現的就一個run方法!!!接口只是run方法的載體,裝黃桃的罐頭盒子!!!核心只要run方法。
我們爲什麼要寫runnable接口的實現類?就是爲了重寫run方法,並且讓線程去執行run方法。
所以,現在我們不要盒子了,直接用手抓着喫!!!

Lambda表達式格式

  • service.submit(() -> System.out.println(Thread.currentThread().getName()));

() -> System.out.println(Thread.currentThread().getName())
Lambda表達式

() 參數列表
-> 做什麼事情,就是對應方法體
箭頭之後的代碼就是正常語句

(參數列表) -> {代碼語句}

Lambda表達式使用,無參數無返回值

Lambda表達式使用,有參數有返回值

Lambda表達式使用前提

  • 有且只有一個缺省屬性爲public abstract方法的接口,例如 Comparator接口,Runnable接口

使用lambda表達式是有一個前後要求約束的方法的參數爲接口類型,或者說局部變量使用調用方法,可以使用lambda也OK

有且只有一個抽象方法的接口,稱之爲【函數式接口】Comparator接口,Runnable接口

反射

Java文件和.class文件的關係

  • Java文件
    Java文件中包含代碼的所有內容,類,接口,成員變量,成員方法…

.class字節碼文件
.java文件 通過 javac編譯工具生成對應的.class字節碼文件
使用JDK中提供的反編譯工具,可以看到.class文件中包含
Class 完整的包名.類名
Field 成員變量,成員變量的名字和成員變量的數據類型[如果是引用數據類型,也是
完整的包名.類名]
Method 成員方法,方法權限修飾符,返回值類型,方法名,形式參數列表數據類型

總結:
.class字節碼文件中,包含了Java文件的所有內容

程序加載過程和.class文件的關係

  • 在Java文件運行過程中,當前程序需要哪一個類參與代碼執行,那麼就需要加載這個類的.class字節碼文件,該.class字節碼文件在程序的加載階段,存在於內存的【代碼區】

.class字節碼文件既然加載到內存的【代碼區】
.class文件中包含對應Java程序的所有內容
代碼區存在一塊空間 ==> .class ==> Java程序的所有內容

Java中的萬物皆對象

  • 在Java代碼中,把在內存代碼區保存的.class字節碼內存空間,看做是一個對象。而該對象中包含了對應Java文件的所有內容。

我的理解:是否和方法名,引用數據類型,數組名之類的類似?都是空間地址。不過他們都是堆區空間地址,而這個對象是代碼區空間地址。

  • 我的理解:java文件反編譯形成的.class文件,會在代碼區佔據一片空間,保存java文件所有內容,也就是構造方法,成員變量,成員方法,註解。而把這片空間看做是一個對象,這個對象是Class類型的。

反射必會方法【重點】

  • Class涉及到的方法(獲取Class類對象)

    • Class Class.forName(String packageNameAndClassName);
      Class類的靜態成員方法,通過完整的包名.類名 獲取對應.class文件的Class對象
      同時也可以作爲.class文件加載的方式。

Class 類名.class;
通過類名.class方法,獲取對應的Class類對象,通常用於方法的參數類型。

Class 類對象.getClass();
通過類對象獲取對應的.class的Class類對象,方法參數,或者說數據類型判斷。

  • Constructor 構造方法類涉及到的方法(通過Class類對象獲取對應類對象的構造方法)

    • 這裏有四種方法

1.public Constructor[] getConstructors();
2.public Constructor[] getDeclaredConstructors();
3.public Constructor getConstructor(Class… initArgumentTypes);
4.public Constructor getDeclaredConstructor(Class… initArgumentTypes);

具體如下:

public Constructor[] getConstructors();
獲取當前Class類對象對應Java文件中,所有【public修飾構造方法的類對象數組】
public:方法權限修飾符
Constructor[]:返回值類型,數組
getConstructors():方法名,並且無參數
下邊的方法就不一一贅述。

public Constructor[] getDeclaredConstructors();
【暴力反射】
獲取當前Class類對象對應Java文件中,所有【構造方法的類對象數組】,包括私有化構造方法。回顧】
new Person();
new Person(1);
因爲這裏利用了重載的知識點,會根據實際【參數類型】,來選擇對應的構造方法。
【推理】
通過Class類對象,獲取指定構造方法,需要根據構造方法的所需的參數數據類型來完成。

public Constructor getConstructor(Class… initArgumentTypes);
根據指定的數據類型,來選擇對應的構造方法,這裏可能會拋出異常。
這裏有且只能獲取獲取類內的指定數據類型public修飾構造方法類對象
Class: 約束數據類型,當前方法所需的參數類型
例如:
這裏需要int類型 int.class
這裏需要String類型 String.class
之類需要Perosn類型 Person.class
異常:
NoSuchMethodException
… : 不定長參數
構造方法需要的參數類型是很多的,有可能無參數,有可能有參數。… 不定長參數
類約束使用,增強代碼的普適性
例如:
這裏無參數 () or (null)
參數類型int類型 (int.class)
參數類型int, String類型 (int.class, String.class)
initArgumentTypes:
參數類型 初始化參數類型複數

public Constructor getDeclaredConstructor(Class… initArgumentTypes);
【暴力反射】
根據指定的數據類型,來選擇對應的構造方法,這裏可能會拋出異常。
這裏可以獲取指定參數類型私有化構造方法和非私有化構造方法
Class: 約束數據類型,當前方法所需的參數類型
例如:
這裏需要int類型 int.class
這裏需要String類型 String.class
之類需要Perosn類型 Person.class
異常:
NoSuchMethodException
… : 不定長參數
構造方法需要的參數類型是很多的,有可能無參數,有可能有參數。… 不定長參數
類約束使用,增強代碼的普適性
例如:
這裏無參數 () or (null)
參數類型int類型 (int.class)
參數類型int, String類型 (int.class, String.class)
initArgumentTypes:
參數名 初始化參數類型複數

  • 通過Class對象創建Class對象對應的類對象

    • Object newInstance(Object… initArguments);
      通過Constructor對象來調用,傳入當前構造方法所需創建對象的初始化參數,創建對象。
      Object: Object類是Java中所有類的基類,這裏可以傳入任意類型的參數
      … : 不定長參數,因爲Constructor類對象在獲取的過程中,約束的參數個數都不確定,
      這裏使用不定長參數來傳入數據
  • Method成員方法涉及到的方法

    • Method[] getMethods();
      獲取類內所有public修飾的成員方法,包括從父類繼承而來的public修飾方法。

Method[] getDeclaredMethods();
暴力反射
獲取類內所有成員方法,但是不包括從父類繼承而來的方法。Method getMethod(String methodName, Class… parameterTypes);
根據指定的方法名和對應的參數類型,獲取對應的public修飾的成員方法
methodName:
方法名,指定獲取的是哪一個方法
parameterTypes:
Class用於約束當前使用你的參數數據類型
… 不定長參數,方法參數個數,順序,有參無參問題
例如:
cls是Class類對象
cls.getMethod(“setName”, String.class);
cls.getMethod(“getName”);

Method getDeclaredMethod(String methodName, Class… parameterTypes);
根據指定的方法名和對應的參數類型,獲取對應的成員方法,包括私有化成員方法,但是不
包括從父類繼承而來的方法
methodName:
方法名,指定獲取的是哪一個方法
parameterTypes:
Class用於約束當前使用你的參數數據類型
… 不定長參數,方法參數個數,順序,有參無參問題
例如:
cls是Class類對象
cls.getMethod(“setName”, String.class);
cls.getMethod(“getName”);
- Object invoke(Object obj, Object… arguments);
通過Method類對象調用,執行對應的方法,需要的參數
obj :
執行當前方法的執行者
arguments:
Object… 不定長參數,當前方法執行所需的實際參數,

  • Field成員變量涉及到方法

    • Field[] getFields();
      獲取類內所有public修飾的成員變量
      Field[] getDeclaredFields();
      獲取類內所有成員變量,包括私有化成員方法

Field getField(String fieldName);
獲取指定變量名的成員變量對象,要求是public修飾的成員變量

Field getDeclaredField(String fieldName);
獲取指定變量名的成員變量對象,包括private私有化修飾的成員變量

void set(Object obj, Object value);
設置指定調用者中對應成員變量的數據
obj : 調用者
value: 對應當前成員變量需要賦值的內容
Object get(Object obj);
獲取指定調用者中指定成員變量的數據
obj: 調用者

  • 給予暴力反射私有化內容的權限操作

    • setAccessible(boolean flag);
      給予Constructor,Method, Field對象,私有化內容,操作權限設置
      true表示可以操作

網絡編程

C/S和B/S

  • C/S

    • 客戶端 服務器軟件結構

服務提供商給予用戶服務需要準備的內容
1. 各大平臺的客戶端
Android iOS PC Windows Linux macOS
QQ 微信 淘寶 JD 劍與遠征
2. 服務器提供服務
軟件更新:
LOL服務器版本更新,同時本地軟件也要進行更新操作。這個操作非常耗時。
熱更新

  • B/S

    • 瀏覽器 服務器軟件結構

服務提供商只要提供數據服務就OK,以及前端數據展示方式
1. 瀏覽器提供商非常非常多
谷歌,火狐,歐朋,Safari,Edge
2. 服務器提供服務
軟件更新:
服務器更新數據,瀏覽器刷新就ok了

網絡通信協議

  • 協議

    • protocol協議

網絡通信協議是要求雙方傳遞數據的計算機必須遵守的,按照對應的網絡傳輸協議,纔可以進入數據的交互和傳遞。

目前網絡段數據傳輸比較常見的協議:
UDP TCP/IP

UDP和TCP/IP區別

  • UDP

      1. 面向無連接,數據傳遞不算特別安全
  1. 因爲面向無連接,傳輸速度快
  2. 因爲面向無連接,數據傳遞存在丟包問題
  3. UDP沒有客戶端和服務器區別,都可以作爲發送端和接收端,相互的

UDP協議使用場景
直播,網絡遊戲
實時的大部分都是UDP

  • TCP/IP

      1. 面向連接,數據傳遞較爲安全
  1. 因爲面向連接,所有傳遞速度較慢
  2. 面向連接,數據傳遞有保障
  3. TCP/IP協議是有明確的服務器和客戶端概念

TCP/IP協議使用場景
客戶端登陸,數據下載,文件傳輸

一個軟件肯定是混合協議的,不是單獨的。

網絡編程的三要素

  • 協議

    • 兩個在於網絡情況下的計算機數據傳遞,都需要對應的協議來完成。
  • IP地址

    • Internet Protocol Address
      當前計算機在網絡中的一個地址編號,類似於手機號號碼
      IP地址有IPv4協議和IPv6協議
      IPv4是一個32位的二進制數,通常展示效果是a.b.c.d 例如 192.168.1.1
      a.b.c.d 各代表0 ~ 255的數字,目前已經消耗殆盡 42億個
      IPv6
      IPv6是能夠保證地球上的每一粒沙子都有一個IP地址。
      128位地址長度,16字節一組
      8組 0x0 ~ 0xFFFF
  • 端口號

    • 端口號是當前應用程序在計算機中的一個編號。可以讓計算機明確知道,當前的數據是給予哪一個程序使用,或者數據從哪一個程序出現的。
      端口號是一個short類型 0 ~ 65535
      0~1024不能用於自定義端口號使用,特定的系統端口號

IP類

  • SUN公司提供給開發使用的IP地址類
    InetAddress

常用方法:
InetAddress getLocalhost();
獲取本機IP地址類對象
InetAddress getByName(String str);
根據指定的主機名獲取對應的IP地址對象
InetAddress[] getAllByName(String str);
獲取指定主機名,或者域名對應的所有IP地址類對象

UDP協議數據傳輸

  • UDP數據傳輸方式

    • User Datagram Protocol
      數據傳遞採用數據包方式傳遞,所有的數據要進行打包操作,並且沒有對應的客戶端服務器概念,有且只有發送端和接收端

Socket 套接字
數據需要進行傳遞操作,在數據傳遞的兩臺計算機當中必須有對應的Socket。這裏採用UDP協議,那麼必須有一個UDP協議的Socket

DatagramSocket();
創建一個發送端UDP協議Socket對象
DatagramSocket(int port);
創建一個接收端UDP協議的Socket對象,這裏需要【監聽】指定端口
發送端數據包的打包方法:
DatagramPacket DatagramPacket(byte[] buf, int length, InetAddress address, int port);
buf: 需要傳遞數據的字節數組
length:是當前字節數組中數據容量字節數
address:接收端IP地址對象
port: 接收端對應的端口號

接收端數據包接收方式
這裏需要準備一個空的數據包
DatagramPacket DatagramPacket(byte[] buf, int length);
buf: 字節緩衝數組,通常是1024整數倍
length: 當前字節緩衝數組的容量

  • 發送端

    • 流程:
  1. 創建UDP服務器對應的發送端Socket
  2. 準備對應數據包,需要帶有指定數據
  3. 發送數據 send
  4. 關閉UDP發送端
  • 接收端

    • 流程:
  1. 打開UDP服務,並且監聽指定端口
  2. 創建新的空數據包
  3. 通過Socket接收數據
  4. 關閉UDP服務接收端
  • UDP數據傳遞丟失問題

    • 這是udp的缺點之一,因爲面向無連接,所以可能會丟數據,類似於玩電腦遊戲丟包,瞬移,卡頓。

網絡不夠好,穩定性不行,帶寬不夠
電腦性能不好

TCP

  • TCP概述

    • TCP相對於UDP比較穩定的傳輸協議,這裏存在三次握手,保證連接狀態,同時有明確的客戶端和服務端之分

TCP服務中需要服務器端先啓動,需要監聽指定端口,等待客戶端連接。

客戶端主動連接服務器,和服務器連接之後,纔可以進行數據交互,服務器不能主動連接客戶端的。

TCP操作而言,Java中提供了兩個Socket

服務端Socket
java.net.ServerSocket;
創建對應的ServerScoket開啓服務器,等待客戶端連接

客戶端Socket(這個比較重要)
java.net.Socket
創建客戶端Scoket,並且連接服務器,同時將Socket發送給服務器綁定註冊。

  • Socket 客戶端Socket

    • 給客戶端提供數據傳輸的符合TCP/IP要求的Socket對象

構造方法 Constructor
Socket(String host, int port);
host是服務器IP地址,port對應服務器程序的端口號
通過指定的服務器IP地址和端口號,獲取TCP連接對象

成員方法 Method
InputStream getInputStream();
獲取Socket對象輸入字節流,可以從服務器獲取對應的數據
InputStream是一個資源,需要在程序退出是關閉
Read

OutputStream getOutputStream();
獲取Sokcet對象輸出字節流,可以發送數據到服務器
OutputStream是一個資源,需要在程序退出是關閉
Write

void close();
關閉客戶端Socket

void shutdownOutput();
禁止當前Socket發送數據

TCP/IP協議對應的Socket是給予IO流實現的。

  • ServerSocket服務端Socket

    • 在服務端開啓Socket服務器

構造方法 Constructor:
ServerSocket(int port);
開啓ServerSocket服務器,並且明確當前服務端口是誰

成員方法 Method:
Socket accept();
監聽並且連接,得到一個Socket對象,同時該方法是一個阻塞方法,會處於一個始終的監聽狀態
返回的是Socket,也就是客戶端Socket對象,獲取到當前Socket對象,相對於獲取到客戶端連接,同時使用的Socket和客戶端一致。

  • TCP協議代碼演示

    • 服務器代碼

      • 流程:
  1. 創建ServerSocket服務器,同時監聽指定端口

  2. 通過accept方法獲取Socket連接,得到客戶端Socket對象

  3. 通過Socket對象,獲取InputStream,讀取客戶端發送數據

  4. 通過Socket對象,獲取OutputStream,發送數據給客戶端

  5. 關閉服務

    • 客戶端代碼

      • 流程:
  6. 創建Socket服務,同時明確連接服務器的IP地址和對應端口號

  7. 通過Socket對象,獲取對應的OutputStream對象,發送數據給服務器

  8. 通過Socket對象,獲取對應的InputStream對象,接收服務器發送數據

  9. 關閉服務

    • 代碼總結

      • 在這裏只是一個小的演示,傳遞的只有一句話,比較小,所以用一個1024的字節數組就可以接收信息了。
        下邊來傳輸比較大的文件,會用到之前的IO流操作。
  • 文件上傳操作

    • 客戶端程序

      • 流程:
  1. 創建對應文件的輸入字節流操作,這裏可以使用緩衝

  2. 啓動Socket

  3. 獲取Socket輸出OutputStream對象,發送數據給服務器

  4. 邊讀邊發

  5. 當文件讀取結束,發送完畢,關閉客戶端

    • 服務端程序

      • 流程:
  6. 開啓服務端服務,創建ServerSocket對象

  7. 明確保存文件的位置,創建對應文件夾的輸出緩衝字節流

  8. 讀取數據,寫入文件

  9. 關閉服務器

    • 目前服務端代碼問題

      • 在上邊的代碼中,我們存在一些邏輯問題

保存的文件名都是一致的,無法保存多個文件。
這裏可以考慮使用UUID作爲文件名

服務端沒有這麼low,代碼肯定不能執行完一個上傳功能就結束

同理,服務端代碼不可能只有一個上傳文件功能
- 服務端代碼優化

		- 代碼

XML

XML概述

  • Extensible Markup Language
    可拓展標記語言

用途:
1. 數據存儲,小型數據庫,存在一定的CRUD操作可行性
2. 網絡端數據的傳輸
3. JavaWEB框架項目配置文件
Spring Druid …

w3c萬維網聯盟指定的規範

基本語法

    1. XML文件後綴名是.xml
  1. XML第一行是對於當前文件的定義聲明
  2. XML文件中有且只有一個根標籤
  3. 屬性值必須使用引號包含,這裏推薦使用雙引號
  4. 標籤必須正確匹配,正確開始和關閉
  5. XML標籤內嚴格區分大小寫

XML文件組成部分

    1. 文檔聲明:
      a. 格式:
      <?xml 屬性列表 ?>
      <?xml version="1.0" encoding="utf-8" ?>
      version: 當前XML文件版本號
      encoding: 編碼方式,這裏建議XML文件的保存編碼集和對應的解析編輯一致。
      standalone:是否依賴於其他文件 [瞭解]
      yes 不依賴, no 依賴
  1. 指令(瞭解)
    這裏可以導入一些CSS樣式
    <?xml-stylesheet type="text/css" href="test.css" ?>

  2. 標籤內容自定義
    規則:
    a. 自定義標籤允許使用英文字母,數字和其他標點符號(_ - .)
    b. 不允許使用數組和標點符號開頭,只能用英文字母
    c. 不允許在自定義標籤內使用xml標記,XML也不行
    d. 名字不允許出現空格

  3. 屬性
    可以給標籤一個屬性,有時候要求ID屬性是惟一的

  4. 文本(瞭解)
    CDATA區,所見即所得,CDATA區內容是完整展示的
    格式:
    <![CDATA[ 數據 ]]>

XML文件數據約束

    1. DTD
      一種簡單的約束方式
      但是存在一定的約束問題
  1. Schema
    一種複雜XML文件約束方式
    非常嚴謹
  • DTD約束
  • Schema約束

XML解析

  • XML解析思路

    • DOM解析
      Document Object Model 文件對象模型
      把XML整個文件看做一個Document對象,每一個節點看做一個Element,節點中有Attribute,或者當前節點中存在Text文本內容。
      DOM是將整個XML文件讀取到計算機內存中,可以進行CRUD操作。
      缺點:
      佔用了大量內存空間
      適用的環境:
      服務器對於XML文件的解析過程。

SAX解析
逐行讀取,給予一定的事件操作。
讀取一行內容,釋放上一行內容,可以有效的節約內存空間
缺點:
不能對XML文件,進行增刪改
適用的環境:
手機讀取解析XML文件時採用的方式。

  • XML文件解析工具

      1. JAXP: SUN提供的一個基本的解析器,支持DOM和SAX兩種解析方式,但是操作很繁瑣,不便於程序員開發。
  1. Dom4j: DOM For Java 一款非常優秀的解析器
    Spring,SpringMVC… 框架中集成的XML解析器

  2. Jsoup: 基於Java完成的對於HTML解析的工具,因爲HTML和XML文件都是標記語言。
    給Jsoup一個URL,頁面地址. Java的小爬蟲,API很多很方便

  3. PULL:
    Android手機上集成的XML解析工具,SAX方式解析

  • Dom4j使用入門

      1. 導包
        目前使用的是第三方工具,不是原生的JDK
        導入第三方Jar包
  1. 設置IDEA

  2. Dom4j涉及到的方法
    SAXReader();
    解析XML文件使用的核心類
    read() --> XML文件Document對象
    Document document = new SAXReader().read(new File("./xml/User.xml"));

    Document對象中可以使用方法
    Element getRootElement();
    獲取當前XML文件的根節點對象

    Element對象中可以使用方法
    List elements();
    當前節點下的所有子節點
    List elements(String name);
    當前節點下所有指定名字的子節點
    Element element();
    獲取當前節點下的第一個子節點
    Element element(String name);
    獲取當前節點下指定名字的第一個子節點
    Attribute getAttribute(String name);
    根據屬性名獲取對應的屬性對象Attribute
    Attribute節點中可以使用String getValue()來獲取對應的節點數據
    String getName();
    獲取當前節點的名字
    String getText();
    獲取當前節點對應的文本數據

  • XML文件保存

    • 流程:
    1. 創建Document對象
    2. 通過Document對象來添加元素
      addElment();
      addAttribute();

Java線程初識

進程是什麼

  • windows電腦中,打開任務管理器,可以看到電腦中執行的每一個程序,每一個程序就是一個進程。

Windows系統是一個多任務系統。
電腦可以同時執行多個程序。

線程是什麼

  • 電腦管家是一個軟件,也是程序 ==> 進程
    電腦可以同時開啓 病毒查殺,垃圾清理,一鍵加速…等功能

每一個功能就可以看做是線程!

一個應用程序 ==> 進程
應用程序的某一個功能 ==> 線程
應用程序中可以同時執行多個功能 ==> 多線程

線程使用的是系統資源,該系統資源你是操作系統分配給當前進程使用的。
多個線程的情況下,同時【搶佔執行】會導致資源緊缺。
線程搶佔過程就類似於進程搶佔過程。

一個Java程序,最少有幾個線程?
2個線程
 main線程
 JVM的GC機制,守護線程。

併發和並行

  • 併發:
    兩個或者兩個以上的事務在同一個時間段發生

並行:
兩個或者兩個以上的事務在同一個時刻發生
宏觀並行,微觀串行

高併發
雙十一
JD 618
12306
中午下課的餐廳
同時在一個時間段以內,很多事情都發生了,這就是高併發。

多線程

  • 多線程的優缺點

    • 優點
    1. 提升資源利用率
    2. 提高用戶體驗

缺點:
1. 降低了其他線程的執行概率
2. 用戶會感受到軟件的卡頓問題
3. 增加的系統,資源壓力
4. 多線程情況下的共享資源問題,線程衝突,線程安全問題

  • 創建自定義線程類的兩種方式

    • class Thread類
      Java中的一個線程類
      Thread類是Runnable接口的實現類,同時提供了很多線程的操作使用的方法。

interface Runnable接口
這裏規定了what will be run?
裏面只有一個方法 run方法

- **方式一:**
自定義線程類,繼承Thread類,重寫run方法
創建自定義線程對象,直接調用start方法,開啓線程


- **方式二:**
自定義線程類,遵從Runnable接口
使用自定義遵從接口Runnable實現類對象,作爲Thread構造方法參數
藉助於Thread類對象和start方法,開啓線程

【推薦】
以上兩種方式,推薦使用方法二,遵從Runnable接口來完成自定義線程,不影響正常的繼承邏輯,並且可以使用匿名內部類來完成線程代碼塊的書寫。

Thread類需要了解的方法

  • 構造方法 Constructor
    Thread();
    分配一個新的線程對象,無目標,無指定名字
    Thread(Runnable target);
    創建一個新的線程對象,並且在創建線程對象的過程中,使用Runnable接口的實現類
    對象作爲執行的線程代碼塊目標
    Thread(String name);
    創建一個新的線程,無指定目標,但是指定當前線程的名字是什麼
    Thread(Runnable target, String name);
    創建一個線程的線程對象,使用Runnable接口實現類對象,作爲執行目標,並且指定name作爲線程名

成員方法:
void setName(String name);
String getName();
以上兩個是name屬性setter和getter方法
void setPriority(int Priority);
設置線程的優先級,非一定執行要求,只是增加執行的概率
優先級數值範圍 [1 - 10] 10最高 1最低 5默認
int getPriority();
獲取線程優先級
void start();
啓動線程對象

public static void sleep(int ms);
當前方法是靜態方法,通過Thread類調用,要求是當前所在線程代碼塊對應的線程,
進行休眠操作,休眠指定的毫秒數
public static Thread currentThread();
當前方法是靜態方法,通過Thread類調用,獲取當前所處代碼塊對應的線程對象。

這些方法必須牢牢記住!

線程安全問題–共享資源能使用問題

  • 例如:
    <<湄公河行動>>
    100張票

淘票票CGV 美團 貓眼
三個銷售渠道,100張票是一個共享資源!!!
三個銷售渠道,可以認爲是三個銷售線程!!!

問題一:
100張票共享資源問題,選什麼來保存?
局部變量:
在方法內,如果run方法執行,存在,run方法當前執行完畢,銷燬。
每一個線程對象中都有run方法,無法滿足共享問題
成員變量:
每一個線程對象中,都有一個對應的成員變量,非共享資源。
靜態成員變量:
屬於類變量,所有的當前類對象,使用的靜態成員變量都是一個,而且一處修改,處處
受影響。【共享資源】

問題二:
資源衝突問題

線程之間會相互搶佔,而且搶佔頻率很快,有可能會導致一張票賣了三次,也就是資源衝突問題
————————————————
版權聲明:本文爲CSDN博主「青檸小魚碼字猴」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_42581682/article/details/104815540

    • 所以爲了解決這個問題,我們用鎖來解決

以下鎖的是方法,無論誰調用,怎麼調用都會鎖住
- 同步代碼塊

	- 格式:

synchronized (/* 鎖對象 */) {
}

特徵:

  1. synchronized 小括號裏面的對象是鎖對象,並且要求如果是多線程的情況下,鎖對象必須是同一個對象。也就是runnable接口實現類對象。
  2. synchronized 大括號中的代碼塊就是需要進行同步的代碼,或者說是加鎖的代碼,大括號裏面的內容,有且只允許一個線程進入。
  3. 同步代碼塊越短越好,在保證安全的情況下,提高性能

問題:

  1. 目前鎖對象感覺很隨意,存在一定的隱患

  2. 代碼層級關係很複雜,看着有點麻煩
    這個方法比較隨意,一把鎖會鎖了多個線程,有隱患

    • 同步方法

      • 定義在線程類內

synchronized 作爲關鍵字來修飾方法,修飾的方法就是對應的同步方法

有且只允許一個線程進入,到底是誰來完成的加鎖操作?

靜態成員方法
鎖對象,是當前類對應的字節碼文件.class
就是類名.class

非靜態成員方法
鎖對象就是當前類對象 this

選擇同步方法是否使用static修飾問題

如果非static修飾,要保證執行的線程對象有且只有一個,因爲鎖對象就是當前線程對象

如果是static修飾,鎖對象具有唯一性,多個線程使用的鎖是同一個鎖。類似於同步代碼塊。

- Lock鎖

	- Java提供了一個對於線程安全問題,加鎖操作相對於同步代碼塊和同步方法更加廣泛的一種操作方式。

對象化操作。
創建Lock構造方法
Lock lock = new ReentrantLock();
多態思想,不理解就先記着這麼用。
方法化操作。
開鎖:
unlock();
加鎖:
lock();

- 三種加鎖方式的總結


	- 一鎖一線程,一鎖多線程問題。

使用對應的鎖操作對應的線程,考慮靜態和非靜態問題。
同步方法和Lock鎖使用。
靜態是一鎖多目標,非靜態是一鎖一目標

涉及到同步問題時,要考慮好鎖對象的選擇問題
同步代碼塊,同步方法,Lock對象

守護線程

  • 守護線程,也稱之爲後臺線程,如果當前主線程GG思密達,守護線程也就GG思密達。

守護線程一般用於:

  1. 自動下載
  2. 操作日誌
  3. 操作監控

方法是通過線程對象
setDeamon(boolean flag);
true爲守護線程
false缺省屬性,正常線程

線程的狀態簡說

  • NEW(新建) 線程剛剛被創建,沒有啓動,沒有調用start方法
    RUNNABLE(可運行) 線程已經可以在JVM中運行,但是是否運行不確定,看當前線程是否擁有CPU執行權
    BLOCKED(鎖阻塞) 當前線程進入一個同步代碼需要獲取對應的鎖對象,但是發現當前鎖對象被其他線程持有,當前線程會進入一個BLOCKED。如果佔用鎖對象的線程打開鎖對象,當前線程持有對應鎖對象,進入Runnable狀態
    WAITING(無限等待) 通過一個wait方法線程進入一個無限等待狀態,這裏需要另外一個線程進行喚醒操作。進入無限等待狀態的線程是無法自己回到Runnable狀態,需要其他線程通過notify或者notifyAll方法進行喚醒操作
    TIMED_WAITING(計時等待) 當前線程的確是等待狀態,但是會在一定時間之後自動回到Runnable狀態,例如 Thread.sleep() 或者是Object類內的wait(int ms);
    TERMINATED(被終止) 因爲Run方法運行結束正常退出線程,或者說在運行的過程中因爲出現異常導致當前線程GG思密達

  • TIMED_WAITING(計時等待)

    • Thread.sleep(int ms);
      在對應線程代碼塊中,當前線程休眠指定的時間。

Object類內 wait(int ms);
讓當前線程進入一個計時等待狀態

  1. 規定的時間及時完畢,線程回到可運行狀態
  2. 在等待時間內,通過其他線程被notify或者notifyAll喚醒

Sleep方法

  1. 調用之後休眠指定時間
  2. sleep方法必須執行在run方法內,纔可以休眠線程
  3. sleep不會打開當前線程佔用的鎖對象。
    ————————————————
    版權聲明:本文爲CSDN博主「青檸小魚碼字猴」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
    原文鏈接:https://blog.csdn.net/qq_42581682/article/details/104818483
  • BLOCKED(鎖阻塞)

    • 線程中有鎖存在,線程需要進入帶有鎖操作的同步代碼,如果鎖對象被別人持有,只能在鎖外等待

鎖阻塞狀態的線程是否能夠搶到鎖對象有很多因素

  1. 優先級問題,非決定因素
  2. CPU執行概率問題。

後期高併發一定會存在多線程操作鎖對象問題,秒殺,搶購…
隊列方式來處理

  • 線程狀態 WAITING(無限等待)

    • 當某一個線程被執行wait()方法,需要等待另外的一個線程進行喚醒操作。

以下三個方法都是Object類內的方法:
public void wait();
在哪一個線程中執行,就會讓當前線程進入一個無限等待狀態。

  1. 所在線程進入無限等待狀態
  2. 開啓【鎖對象】

public void notify();
喚醒和當前鎖對象有關的無限等待線程中的一個,隨機選擇。

  1. 喚醒一個無限等待狀態線程
  2. 開啓【鎖對象】

public void notifyAll();
喚醒所有和當前鎖對象有關的無限等待線程

  1. 喚醒所有線程
  2. 開啓【鎖對象】
  3. 線程進入鎖對象搶佔過程,就有可能進入一個鎖阻塞狀態。
    ————————————————
    版權聲明:本文爲CSDN博主「青檸小魚碼字猴」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
    原文鏈接:https://blog.csdn.net/qq_42581682/article/details/104818483

線程通信

  • 共享資源處理問題

    • 現在存在兩個完全無關的線程:生產者和消費者,但是商品會作爲他們兩者之間的共享資源。
      生產者和消費者中都有一個成員變量 商品類型

【解決方案】
創建生產者或者消費者線程對象時,使用同一個商品類對象,作爲構造方法參數進行初始化操作
- 代碼

	- 子主題 1

線程池

我們在之前的線程學習中,都是之間創建新的線程,顯性線程,用的時候開啓,用完銷燬,效率低且不安全
而且我們看到在阿里巴巴代碼規範規約中也是不建議顯式創建線程,建議使用線程池。

- 不管是繼承Thread還是遵從Runnable接口,都需要重寫Run方法,而且每一個線程對象有且只能執行一次,之後就會被銷燬。

利用Runnable接口來提供執行目標,而且藉助於Thread執行線程。
- 用生活中的例子來理解:

一個餐廳
服務人員
餐廳會按照餐桌比例安排服務員人數。
每一個服務員我們都可以看做是一個線程對象
需要告知服務器做什麼事情就可以了,相對於告知線程對象執行目標是什麼
當你來餐廳之前,服務員在這裏,你走之後,服務員依然在這類。

線程池 ==> 可以容納多個線程的容器

程序可以從線程池獲取線程來完成目標代碼
同時也可以將線程歸還給線程池。
省去了創建線程和銷燬線程這樣非常繁瑣的操作。節省時間。

- 線程池使用

public static ExecutorService newFixedThreadPool(int nThreads);
得到一個線程池對象,初始化參數是要求的當前線程池中的線程數

在這行代碼中, newFixedThreadPool是ExecutorService類中的方法
返回值是ExecutorService,參數是int類型的線程數量。
創建代碼示例爲:

ExecutorService service = Executors.newFixedThreadPool(5);

public Future submit(Runnable target);

從線程池中獲取一個線程對象,並且執行給定的Runnable接口實現類對象作爲執行目標

XMind: ZEN - Trial Version

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