Socket編程
一、網(wǎng)絡(luò)基礎(chǔ)知識(shí)
兩臺(tái)計(jì)算機(jī)要通過網(wǎng)絡(luò)進(jìn)行通信,必須具備:
a、唯一的標(biāo)識(shí)(IP地址);
b、需要共同的語言(協(xié)議);
c、辨別不同應(yīng)用程序(端口號(hào))。
1、IP地址:
每臺(tái)計(jì)算機(jī)的唯一標(biāo)識(shí),用來區(qū)分網(wǎng)絡(luò)中的不同主機(jī),是兩臺(tái)主機(jī)進(jìn)行網(wǎng)絡(luò)通信必不可少的。IPv4
2、協(xié)議:
a、TCP/IP協(xié)議:目前世界上應(yīng)用最為廣泛的協(xié)議。是以TCP和IP為基礎(chǔ)的不同層次上多個(gè)協(xié)議的集合。也稱為:TCP/IP協(xié)議族 或者 TCP/IP協(xié)議棧。
b、TCP: Transmission Control Protocol 傳輸控制協(xié)議
c、IP :Internet Protocol 互聯(lián)網(wǎng)協(xié)議
d、TCP/IP模型(網(wǎng)絡(luò)分層):
1、物理層;網(wǎng)線。。。
2、數(shù)據(jù)鏈路層
3、網(wǎng)絡(luò)層
4、傳輸層:TCP/IP協(xié)議
5、應(yīng)用層:HTTP超文本傳輸協(xié)議、FTP文件傳輸協(xié)議、SMTP簡單郵件傳送協(xié)議、Telnet遠(yuǎn)程登錄服務(wù)。
3、端口號(hào):
a、用于區(qū)分不同的應(yīng)用程序;
b、端口號(hào)范圍為0-65535,其中0-1023為系統(tǒng)所保留;
c、IP地址和端口號(hào)組成了所謂的Socket,Socket是網(wǎng)絡(luò)上運(yùn)行的程序之間雙向通信鏈路的終結(jié)點(diǎn),是TCP和UDP的基礎(chǔ)。
d、常用端口號(hào)-- http: 80; ftp; 21; telnet; 23。
JAVA中得網(wǎng)絡(luò)支持
針對網(wǎng)絡(luò)通信的不同層次,Java提供的網(wǎng)絡(luò)功能有四大類:
1、InetAddress:用于標(biāo)識(shí)網(wǎng)絡(luò)上的硬件資源。(IP地址)
2、URL:統(tǒng)一資源定位符---通過URL可以直接讀取或?qū)懭刖W(wǎng)絡(luò)上得數(shù)據(jù)。
3、Sockets:使用TCP協(xié)議實(shí)現(xiàn)網(wǎng)絡(luò)通信的Socket相關(guān)的類。
4、Datagram:使用UDP協(xié)議,將數(shù)據(jù)保存在數(shù)據(jù)報(bào)中,通過網(wǎng)絡(luò)進(jìn)行通信
1.InetAddress類沒有構(gòu)造方法,所以不能直接new出一個(gè)對象;
可以通過InetAddress類的靜態(tài)方法獲得InetAddress的對象;
InetAddress.getLocalHost();
InetAddress.getByName("");
2.類主要方法:
String - address.getHostName();
String - address.getHostAddress();
public static InetAddress getByName(String host) throws UnknownHostException
在給定主機(jī)名的情況下確定主機(jī)的 IP 地址。
主機(jī)名可以是機(jī)器名(如 "java.sun.com"),也可以是其 IP 地址的文本表示形式
// 獲取本機(jī)的InetAdress實(shí)例
InetAddress address = InetAddress.getLocalHost();
輸出:hostName/hostAdress
// 根據(jù)主機(jī)名稱獲取InetAdress實(shí)例
InetAddress address2 = InetAddress.getByName("hostName");
// 根據(jù)IP地址獲取實(shí)例
InetAddress address2 = InetAddress.getByName("ipAdress");
URL
url:統(tǒng)一資源定位符:表示internet上的網(wǎng)絡(luò)資源<br>
協(xié)議+資源名稱<br>
url常用方法:<br>
存在java.net包中,提供創(chuàng)建url/子url,獲取url等方法<br>
第一步:創(chuàng)建實(shí)例<br>
URL imooc=new URL("http://www.imooc.com");<br>
//在原有url下再創(chuàng)建url<br>
URL url=new URL(imooc,"/index.html?username=tom#test")<br>
//獲取url的信息<br>
url.getProtocol();//獲取協(xié)議http<br>
url.getHost();//獲取主機(jī)www.imooc.com<br>
url.getPort();//獲取端口號(hào):-1<br>
url.getPath();//獲取文件路徑/index.html<br>
url.getFile();//獲取文件名/index.html?username=tom<br>
url.getRef();//獲取相對路徑test<br>
url.getQuery();//查詢字符串username=tom<br>
注:創(chuàng)建url時(shí)沒有指定端口號(hào)則getPort方法返回-1,協(xié)議不同會(huì)使用默認(rèn)端口
2url讀取網(wǎng)頁內(nèi)容:<br>
URL url=new URL("http://www.baidu.com");<br>
//獲取輸入流通過openStream方法<br>
InputStream is=url.openStream();<br>
//轉(zhuǎn)化成字符輸入流<br>
InputStream isr=new InputStreamReader(is);<br>
//加緩沖提高讀取效率<br>
BufferedReader br=new BufferedReader();<br>
String date=br.teadline();
while(date.next()){System.out.print(date);
date=br.readLine();
}
完成后要關(guān)閉資源相關(guān)資源:br,isr字符輸入流,is字節(jié)輸入流
注:如果輸出是亂碼則要在is字節(jié)輸入流中規(guī)定編碼為
InputStream isr=new InputStreamReader(is,"utf8");<br>
二、通信過程(Socket通信模型):
1、在服務(wù)端建立一個(gè)ServerSocket,綁定相應(yīng)的端口,并且在指定的端口進(jìn)行偵聽,等待客戶端的連接。
2、當(dāng)客戶端創(chuàng)建連接Socket并且向服務(wù)端發(fā)送請求。
3、服務(wù)器收到請求,并且接受客戶端的請求信息。一旦接收到客戶端的連接請求后,會(huì)創(chuàng)建一個(gè)鏈接socket,用來與客戶端的socket進(jìn)行通信。通過相應(yīng)的輸入/輸出流進(jìn)行數(shù)據(jù)的交換,數(shù)據(jù)的發(fā)送接收以及數(shù)據(jù)的響應(yīng)等等。
4、當(dāng)客戶端和服務(wù)端通信完畢后,需要分別關(guān)閉socket,結(jié)束通信。
ServerSocket常用方法:
ServerSocket(int port)——?jiǎng)?chuàng)建并綁定到特定端口的服務(wù)器套接字
accept()——偵聽并接受到此套接字的連接
close()——關(guān)閉此套接字
getInetAddress()——得到ServerSocket對象綁定的IP地址。如果ServerSocket對象未綁定IP地址,返回0.0.0.0。
getLocalPort()——返回此套接字在其上偵聽的端口
Socket常用方法:
Socket(InetAddress address, int port)——?jiǎng)?chuàng)建一個(gè)套接字并將其連接到指定ip地址的指定端口號(hào)
Socket(String host, int port)——?jiǎng)?chuàng)建一個(gè)套接字并將其連接到指定主機(jī)上的指定端口號(hào)
close()——關(guān)閉此套接字
getInetAddress()——返回套接字連接的地址
getInputStream()——返回此套接字的輸入流
getOutputStream——返回此套接字的輸出流

實(shí)例
步驟:
(1)創(chuàng)建ServerSocket和Socket
(2)打開連接到Socket的輸入/輸出操作
(3)按照協(xié)議對Socket進(jìn)行讀/寫操作
(4)關(guān)閉輸入輸出流,關(guān)閉Socket
服務(wù)器端:
(1)創(chuàng)建ServerSocket對象,綁定監(jiān)聽器
(2)通過accept()方法監(jiān)聽客戶端請求
(3)連接建立以后通過讀取客戶端發(fā)送請求消息
(4)通過輸出流向客戶端發(fā)送響應(yīng)信息
(5)關(guān)閉資源
客戶端:
(1)創(chuàng)建Socket對象,指明需要連接的服務(wù)器地址和端口號(hào)(1023以后的端口)
(2)連接建立后,通過輸出流向服務(wù)器端請求
(3)通過輸入流獲取服務(wù)器響應(yīng)信息
(4)關(guān)閉資源
常用I/O操作
InputStream is = socket.getInputStream();//字節(jié)輸入流
InputStreamReader isr = new InputStreamReader(is)//將字節(jié)輸入流轉(zhuǎn)換為字符輸入流
BufferedReader br = new BufferedReader(isr);//為輸入流添加緩沖
br.readLine()按行讀取
flush()刷新緩存
使用多線程實(shí)現(xiàn)多客戶端的
主線程負(fù)責(zé)創(chuàng)建socket
* 一個(gè)線程用來讀取
* 一個(gè)線程用來寫入,用兩個(gè)內(nèi)部類
* 要用多線程實(shí)現(xiàn),send線程和recived線程同時(shí)訪問buff數(shù)據(jù)區(qū)。
* 發(fā)送完成后notify,接收線程。接收線程自身wait
* 接收的說,我先wait一下,可能緩存中還沒有數(shù)據(jù),我會(huì)拿到空值得。
* 發(fā)送的說Ok,我先寫,寫完了我notifyall你。我就一直鎖著,這樣默契的合作了。變成并行處理了
每個(gè)客戶端連接服務(wù)端都會(huì)產(chǎn)生一個(gè)新的socket。
UDP編程
1、UDP協(xié)議(用戶數(shù)據(jù)報(bào)協(xié)議)是無連接、不可靠、無序的。
2、UDP協(xié)議以數(shù)據(jù)報(bào)作為數(shù)據(jù)傳輸?shù)妮d體。
3、使用UDP進(jìn)行數(shù)據(jù)傳輸時(shí),首先需要將要傳輸?shù)臄?shù)據(jù)定義成數(shù)據(jù)報(bào)(Datagram),在數(shù)據(jù)報(bào)中指明所要達(dá)到的Socket(主機(jī)地址和端口號(hào)),然后在將數(shù)據(jù)報(bào)發(fā)生出去。
4、相關(guān)操作類:DatagramPacket:表示數(shù)據(jù)報(bào)包
DatagramSocket:進(jìn)行端到端通信的類
DatagramPacket類構(gòu)造方法:
1、DatagramPacket(byte[] buf,int length)//接受長度為length的數(shù)據(jù)包
2、DatagramPacket(byte[] buf,int length,InetAddress address,int port)//將指定長度的字節(jié)發(fā)生到指定主機(jī)的指定端口
DatagramSocket類
1、構(gòu)造方法:DatagramSocket();
DatagramSocket(int port,InetAddress laddr);
2、close();//關(guān)閉DatagramSocket
3、getInetAddress();//獲取地址
4、getPort();//獲取端口號(hào)
5、send(DatagramPacket p);//從此套接字發(fā)送數(shù)據(jù)包
recrive(DatagramPacket p);//從此套接字接收數(shù)據(jù)包
服務(wù)器端實(shí)現(xiàn)步驟:
1、創(chuàng)建DatagramSocket,指定端口號(hào)
2、創(chuàng)建DatagramPacket
3、接收客戶端發(fā)送的數(shù)據(jù)信息
4、讀取數(shù)據(jù)
客戶端:
1、定義發(fā)送信息
2、創(chuàng)建DatagramPacket:包含將要發(fā)送信息
3、創(chuàng)建DatagramSocket
4、發(fā)送數(shù)據(jù)
服務(wù)端具體代碼:
1、創(chuàng)建服務(wù)器端DatagramSocket
DatagramSocket socket=DatagramSocket(8800);
2、創(chuàng)建數(shù)據(jù)報(bào),用戶接收客戶端發(fā)送的數(shù)據(jù)
byte[] data=new byte[1024];
DatagramPacket packet=new datagramPacket(data,data.length);
3、接收客戶端發(fā)送的數(shù)據(jù)
socket.receive(packet);//會(huì)處于阻塞,直到接收到數(shù)據(jù)報(bào)
4、讀取數(shù)據(jù)
String info=new String(data,0,packet.getLength());
System.out.println("客戶端說"+info)
UDP編程-服務(wù)器向客戶端響應(yīng)數(shù)據(jù)(與客戶端向服務(wù)器發(fā)送數(shù)據(jù)類似)
1、定義客戶端的地址、端口號(hào)、數(shù)據(jù)。通過DatagramPacket的.getAddress()方法獲取客戶端的地址,通過.getPort()方法獲取端口號(hào)。
2、創(chuàng)建數(shù)據(jù)報(bào)DatagramPacket,包含響應(yīng)的數(shù)據(jù)信息。
3、響應(yīng)客戶端。調(diào)用DatagramSocket的.send()方法。
4、關(guān)閉資源
UDP編程-客戶端接受服務(wù)器端響應(yīng)的數(shù)據(jù)
1、創(chuàng)建數(shù)據(jù)報(bào)DatagramPacket,用于接受服務(wù)器端響應(yīng)的數(shù)據(jù)。首先創(chuàng)建一個(gè)字節(jié)數(shù)組。
2、接受服務(wù)器端響應(yīng)的數(shù)據(jù)。調(diào)用DatagramPacket的.receive()方法。
3、讀取數(shù)據(jù)。將字節(jié)數(shù)組轉(zhuǎn)變?yōu)樽址?4、關(guān)閉資源。
同步模式:
同步模式的特點(diǎn)是在通過Socket進(jìn)行連接、接收、發(fā)送數(shù)據(jù)時(shí),客戶機(jī)和服務(wù)器在接收到對方響應(yīng)前會(huì)處于阻塞狀態(tài),即一直等到收到對方請求進(jìn)才繼續(xù)執(zhí)行下面的語句??梢姡侥J街贿m用于數(shù)據(jù)處理不太多的場合。當(dāng)程序執(zhí)行的任務(wù)很多時(shí),長時(shí)間的等待可能會(huì)讓用戶無法忍受。
異步模式:
異步模式的特點(diǎn)是在通過Socket進(jìn)行連接、接收、發(fā)送操作時(shí),客戶機(jī)或服務(wù)器不會(huì)處于阻塞方式,而是利用callback機(jī)制進(jìn)行連接、接收、發(fā)送處理,這樣就可以在調(diào)用發(fā)送或接收的方法后直接返回,并繼續(xù)執(zhí)行下面的程序。可見,異步套接字特別適用于進(jìn)行大量數(shù)據(jù)處理的場合。
Socket 總結(jié)
1、多線程的優(yōu)先級(jí)(死循環(huán)中注意設(shè)置優(yōu)先級(jí)問題。)建議降低優(yōu)先級(jí)。
2、關(guān)閉socket流,而不提倡關(guān)閉輸入輸出流。
3、使用tcp通信傳輸對象更符合面向?qū)ο缶幊痰乃枷搿?4、通過socket編程傳輸文件的功能模塊是:通過io流讀取文件字符流進(jìn)行傳輸。
深入淺出Java多線程
概念
1.進(jìn)程:是程序或任務(wù)的執(zhí)行的過程,具有動(dòng)態(tài)性,它持有資源(共享內(nèi)存,共享文件)和線程
2.線程:系統(tǒng)中最小的執(zhí)行單元。 比如一個(gè)軟件里邊的各種任務(wù)就是線程。同一進(jìn)程中有多個(gè)線程,線程共享進(jìn)程的資源
3.線程交互:即線程通信
4.線程之間存在同步和互斥
線程同步互斥的4種方式
臨界區(qū)(Critical Section)、互斥量(Mutex)、信號(hào)量(Semaphore)、事件(Event)的區(qū)別
1、臨界區(qū):通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數(shù)據(jù)訪問。在任意時(shí)刻只允許一個(gè)線程
對共享資源進(jìn)行訪問,如果有多個(gè)線程試圖訪問公共資源,那么在有一個(gè)線程進(jìn)入后,其他試圖訪問公共資源的線程將被
掛起,并一直等到進(jìn)入臨界區(qū)的線程離開,臨界區(qū)在被釋放后,其他線程才可以搶占。
2、互斥量:采用互斥對象機(jī)制。 只有擁有互斥對象的線程才有訪問公共資源的權(quán)限,因?yàn)榛コ鈱ο笾挥幸粋€(gè),所以能保
證公共資源不會(huì)同時(shí)被多個(gè)線程訪問?;コ獠粌H能實(shí)現(xiàn)同一應(yīng)用程序的公共資源安全共享,還能實(shí)現(xiàn)不同應(yīng)用程序的公共
資源安全共享
3、信號(hào)量:它允許多個(gè)線程在同一時(shí)刻訪問同一資源,但是需要限制在同一時(shí)刻訪問此資源的最大線程數(shù)目
4、事 件: 通過通知操作的方式來保持線程的同步,還可以方便實(shí)現(xiàn)對多個(gè)線程的優(yōu)先級(jí)比較的操作
Thread常用方法
sleep(long millis, int nanos) 線程休眠 millis休眠的時(shí)間,單位是毫秒,可以精確到納秒
join(long millis, int nanos) 調(diào)用線程 可以讓其它線程等待自己運(yùn)行,直到結(jié)束
static void yield() 當(dāng)前運(yùn)行線程釋放處理器資源并且重新去競爭處理器資源
static Thread currentThread() 返回當(dāng)前正在處理器上運(yùn)行的線程的引用
重載的幾個(gè)形式
1.沒有參數(shù),指明了其它的線程一定要等待正在執(zhí)行的線程執(zhí)行完畢之后,都會(huì)獲得運(yùn)行的機(jī)會(huì)
2.nanos是要把精確度改變,可改成納秒

兩種方法實(shí)現(xiàn)線程:
1、繼承 Thread 類
class MyThread extends Thread{};
Thread myThread = new MyThread();
myThread.start();
2、實(shí)現(xiàn)Runnable類
class MyRunnable implements Runnable{}
Thread myRunnable = new Thread(new MyRunnable);
myRunnable.start();
3、Thread啟動(dòng)后執(zhí)行run()方法
4、若實(shí)現(xiàn)接口通過Thread.currentThread().getName()方法獲取當(dāng)前線程名稱,繼承Thread則getName()方法獲取當(dāng)前線程。
1.加入join是為了讓舞臺(tái)線程最后停止,如果不加有可能舞臺(tái)線程結(jié)束,軍隊(duì)線程還未停止,就好比導(dǎo)演喊停,演員還在
演!可以在join后面加入測試語句System.out.println("舞臺(tái)結(jié)束!");,然后去掉或者保留join觀察效果。
2.volatile 關(guān)鍵字 保證了線程可以正確地讀取其他線程寫入的值,如果不寫成volatile,由于可見性的問題,當(dāng)前線程有可能
不能讀到這個(gè)值//可見性JMM(JAVA內(nèi)存模型)happens-before原則、可見性原則
用volatile修飾的變量,線程在每次使用變量的時(shí)候,都會(huì)讀取變量修改后的值
3.Thread.yield();//讓出處理器時(shí)間,公平競爭
線程執(zhí)行過程中幾個(gè)重要的方法
sleep(); 讓線程休眠一段時(shí)間,
yield(); 讓出當(dāng)前線程的執(zhí)行權(quán)限,讓線程調(diào)度重新選擇線程進(jìn)行執(zhí)行;
join(); 讓其他線程都停止,等待當(dāng)前線程執(zhí)行完畢。
當(dāng)某個(gè)線程使用join()方法加入到另一個(gè)線程時(shí),另一個(gè)線程會(huì)等待該線程執(zhí)行完畢后再繼續(xù)執(zhí)行。
stop方法使得線程戛然而止,完成了什么工作,哪些工作還沒有做,都不知道,且清理工作也沒有做,所以不是正確的停止線程方法
正確的停止線程方法是,在線程執(zhí)行中設(shè)置狀態(tài)標(biāo)識(shí),通過控制標(biāo)識(shí)來控制線程正常完整的執(zhí)行結(jié)束線程
volatile是保證所有子線程里的變量都能同步到主內(nèi)存里變量的值
不要用stop()方法結(jié)束線程
如何正確停止線程?
--使用退出標(biāo)志
如本文:volatile boolean keepRunning=true;
這樣做的好處是:使得線程有機(jī)會(huì)使得一個(gè)完整的業(yè)務(wù)步驟被完整地執(zhí)行,在執(zhí)行完業(yè)務(wù)步驟后有充分的時(shí)間去做代碼的清理工作,使得線程代碼在實(shí)際中更安全
@Java線程——如何正確停止線程
一、錯(cuò)誤一:stop()方法
1、not stop:stop()方法會(huì)使線程戛然而止
2、使程序突然中止,無法完成完整的業(yè)務(wù)步驟,也無法進(jìn)行清理工作
二、錯(cuò)誤二:interrupt()方法
1、interrupt()方法只能設(shè)置interrupt標(biāo)志位(且在線程阻塞情況下,標(biāo)志位會(huì)被清除,更無法設(shè)置中斷標(biāo)志位),無法停止線程
三、正確方法:設(shè)置退出標(biāo)志
1、使用退出標(biāo)志位來停止while循環(huán)
2、完成最后一次業(yè)務(wù)后跳出while循環(huán)后,之后進(jìn)行一些清理工作
線程停止:
1、調(diào)用stop()方法會(huì)使線程戛然停止,而無法知道線程任務(wù)完成情況,官方已經(jīng)不推薦使用。
2、interrupt()方法設(shè)置線程的標(biāo)識(shí)位,并在線程中判斷標(biāo)志位的狀態(tài),從而結(jié)束線程,但是當(dāng)在線程中開啟了另外的線程
時(shí),比如在線程中Tread.sleep(),這時(shí)候調(diào)用interrupt()方法設(shè)置標(biāo)志位可能設(shè)置的是你想要停止的線程,也可能是想要停
止的線程中的線程的標(biāo)志位,因此interrupt()方法也并不能很好的結(jié)束線程。
3、第三種方法,在線程的類聲明一個(gè)volatile變量來記錄線程的狀態(tài),相當(dāng)于interrupt()方法那樣,volatile關(guān)鍵字表示線程
中的變量可以接受外部其他線程改變。因此可以在需要停止的地方設(shè)置volatile聲明的變量的值設(shè)置為狀態(tài),并在執(zhí)行run()
函數(shù)里判斷是否結(jié)束。
線程交互
@Java線程——線程交互——爭用條件
1、當(dāng)多個(gè)線程同時(shí)共享訪問同一數(shù)據(jù)(內(nèi)存區(qū)域)時(shí),每個(gè)線程都嘗試操作該數(shù)據(jù),從而導(dǎo)致數(shù)據(jù)被破壞(corrupted),這種現(xiàn)象稱為爭用條件
2、原因是,每個(gè)線程在操作數(shù)據(jù)時(shí),會(huì)先將數(shù)據(jù)初值讀【取到自己獲得的內(nèi)存中】,然后在內(nèi)存中進(jìn)行運(yùn)算后,重新賦值到數(shù)據(jù)。
3、爭用條件:線程1在還【未重新將值賦回去時(shí)】,線程1阻塞,線程2開始訪問該數(shù)據(jù),然后進(jìn)行了修改,之后被阻塞的線程1再獲得資源,而將之前計(jì)算的值覆蓋掉線程2所修改的值,就出現(xiàn)了數(shù)據(jù)丟失情況
@Java線程——線程交互——互斥與同步
一、互斥
1、同一時(shí)間,只能有一個(gè)線程訪問數(shù)據(jù)
二、同步
1、是一種通信機(jī)制,一個(gè)線程操作完成后,以某種方式通知其他線程
三、實(shí)現(xiàn)方法
1、【互斥】構(gòu)建鎖對象(Object objLock),通過synchronized(lockObj){ 互斥的代碼塊 }
2、加鎖操作會(huì)開銷系統(tǒng)資源,降低效率。
3、在某線程的條件不滿足任務(wù)時(shí),使用lockObj.wait()對線程進(jìn)行阻擋,防止其繼續(xù)競爭CPU資源,滯留在wait set中,等待喚醒,【喚醒后繼續(xù)完成業(yè)務(wù)】
4、【同步】在某一代碼正確執(zhí)行完業(yè)務(wù)后,通過lockObj.notifyAll()喚醒所有在lockObj對象等待的線程

同步是兩個(gè)線程之間的一種交互的操作(一個(gè)線程發(fā)出消息另外一個(gè)線程響應(yīng))。
同步的實(shí)現(xiàn):wait();notify();notifyAll();這三個(gè)方法都是屬于Java中的Object對象的成員函數(shù)。
調(diào)用wait();和notifyAll();方法使線程進(jìn)入等待或者喚醒不是在同一個(gè)線程的同一次操作中執(zhí)行的,當(dāng)操作結(jié)束,喚醒了所有的等待線程之后,線程又將有著公平的機(jī)會(huì)競爭CPU資源。
注意:notify();方法喚醒wait set 中的一條線程使其具有競爭CPU的機(jī)會(huì),具體喚醒那一條線程是隨機(jī)的由Java的底層算法決定,我們不能去控制。
通過synchronized關(guān)鍵字為臨界區(qū)(critical)加鎖,這樣在線程競爭資源時(shí),當(dāng)某一條線程獲得鎖進(jìn)入臨界區(qū)后,其他線程將無法再次獲取鎖進(jìn)入臨界區(qū)(critical),直到獲得鎖的線程退出臨界區(qū)(critical),釋放鎖資源。Java的語法保證了同一時(shí)間只能有一條線程可以獲得lockObject。

重點(diǎn)回顧:
1,創(chuàng)建線程的方法--繼承Thread--實(shí)現(xiàn)Runnable接口----線程的基本操作
2,可見性--volatile關(guān)鍵字
3,征用條件
4,互斥與同步-----synchronized----wait/notify/notifyAll