5月30日學習內容
校驗一個多線程程序是否有安全問題的隱患的前提條件:
1)當前程序是否是多線程環境
2)是否有共享數據
3)是否有多條語句對共享數據進行操作
鎖對象格式:
synchronized(鎖對象){
針對多條語句對共享數據操作代碼;
}
鎖對象:一定要同一個鎖(每個線程只能使用同一把鎖)
售票問題
package org.westos_05;
public class SellTicket implements Runnable {
//定義100張票
private int tickets = 100 ;
private Object obj = new Object() ;
private Demo d = new Demo() ;
@Override
public void run() {
while(true) {
//t1,t2,t3 synchronized(d) { //門的開和關 //t1進來,門會關掉 //t2進來,門關掉 //t3進來,門關掉 if(tickets>0) { try { //0.1 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"正在出售第"+(tickets--)+"張票"); //窗口1正在出售第100張票 //窗口2正在出售第99張票 //窗口3正在出售98張票 //.... //雖然加入延遲操作,就是synchronized,不會存在0或者負票了 } } }
}
}
public class SellTicketDemo {
public static void main(String[] args) {
//創建資源類對象(共享資源類/目標對象)
SellTicket st = new SellTicket() ;
//創建線程類對象
Thread t1 = new Thread(st, "窗口1") ;
Thread t2 = new Thread(st ,"窗口2") ;
Thread t3 = new Thread(st, "窗口3") ;
//啟動線程
t1.start();
t2.start();
t3.start();
}
}
還可以將鎖對象進行包裝,如果包裝成靜態類,鎖對象為類名.class;
//線程安全的類
StringBuffer sb = new StringBuffer() ;
Vector<String> v = new Vector<String>() ;
Hashtable<String, String> hm = new Hashtable<String,String>() ;
//Vector<String>它線程安全的類,還是不習慣使用這個集合,通過ArrayList集合:線程不安全的類
List<String> array = new ArrayList(); //線程不安全的類
//public static <T> List<T> synchronizedList(List<T> list)
//返回指定列表支持的同步(線程安全的)列表
List list = Collections.synchronizedList(array) ; //線程安全的方法
// Jdk5.0以後,java提供了一個具體的鎖: 接口:Lock
private Lock lock= new ReentrantLock(); //顯示獲取鎖的前提,一定要創建Lock接口對象
Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。此實現允許更靈活的結構
可以使用Lock鎖進行具體的鎖定操作類 提供了具體的實現類:ReentrantLock
加鎖並且去釋放鎖
package org.westos_07;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTicket implements Runnable {
// 定義票
private int tickets = 100;
// Object obj = new Object();
// Jdk5.0以後,java提供了一個具體的鎖: 接口:Lock
private Lock lock= new ReentrantLock(); //顯示獲取鎖的前提,一定要創建Lock接口對象
@Override
public void run() {
while (true) {
try { //try...finally
lock.lock(); // 獲取鎖 syncrhonized(obj)
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票");
}
} finally {//釋放鎖
if(lock!=null) {
lock.unlock();
}
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
SellTicket st = new SellTicket() ;
Thread t1 = new Thread(st,"窗口1") ;
Thread t2 = new Thread(st,"窗口2") ;
Thread t3 = new Thread(st,"窗口3") ;
//啟動線程
t1.start();
t2.start();
t3.start();
}
}
5.消費者生產者問題解密死鎖;
package org.westos_11;
public class Student {
String name ;
int age ;
boolean flag; //默認沒有數據,如果是true,說明有數據
}
package org.westos_11;
//消費者線程
public class GetThread implements Runnable {
private Student s ;
public GetThread(Student s) {
this.s = s ;
}
@Override
public void run() {
//輸出該學生數據
// Student s = new Student() ;
while(true) {
synchronized (s) {
//如果本身消費者有數據
if(!s.flag) {
try {
s.wait();//和網絡編程中TCP編程裏面的accept() 都屬於阻塞式方法
//消費線程等待,等待該線程先輸出這些數據(立即釋放鎖對象)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name +"----"+s.age);//高圓圓---27
//如果沒有數據類,
s.flag = false ;
//通知t1線程,趕緊產生數據
s.notify(); //喚醒單個線程
}
//張楊---27
}
}
}
public SetThread(Student s) {
this.s = s ;
}
//定義一個變量
private int x = 0 ;
@Override
public void run() {
//設置學生數據
// Student s = new Student() ;
while(true) {
synchronized (s) {
//判斷有沒有數據的情況
if(s.flag) {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x%2 ==0) {
s.name = "高圓圓" ; //高圓圓---27
s.age = 27 ;
}else {
s.name = "張楊";
//張楊
s.age = 28 ;
}
x++ ;
//如果有數據了,更改flag值
s.flag = true ;//有數據了
//通知t2線程消費數據,喚醒
s.notify(); //喚醒t2線程,喚醒之後t1,t2都互相搶占
}
}
}
}
public class StudentDemo {
public static void main(String[] args) {
//針對同一個對象進行操作
Student s = new Student() ;
//創建線程類對象
SetThread st = new SetThread(s) ;
GetThread gt = new GetThread(s) ;
//創建線程了對象
Thread t1 = new Thread(st) ; //生產者
Thread t2 = new Thread(gt) ;//消費者
//啟動線程
t1.start();
t2.start();
}
}public class StudentDemo {
public static void main(String[] args) {
//針對同一個對象進行操作
Student s = new Student() ;
//創建線程類對象
SetThread st = new SetThread(s) ;
GetThread gt = new GetThread(s) ;
//創建線程了對象
Thread t1 = new Thread(st) ; //生產者
Thread t2 = new Thread(gt) ;//消費者
//啟動線程
t1.start();
t2.start();
}
}
線程池問題
package org.westos_13;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
線程池:多個線程執行完畢,它會重新回到線程池中,等待被利用,不會變成垃圾!
和線程池有關的類
類 Executors: 一種工廠類
方法:
和線程池的創建有關系
public static ExecutorService newFixedThreadPool(int nThreads)
創建一個可重用固定線程數的線程池
ExecutorService:可以執行異步任務
創建一個線程池,執行接口中的方法
提交:Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future
Future:接口
Future 表示異步計算的結果
線程池調用完畢可以關閉的
void shutdown():關閉之前,會提交剛才的任務
public class ExceutorsDemo {
public static void main(String[] args) {
//創建一個線程池
ExecutorService pool = Executors.newFixedThreadPool(2) ;//創建一個線程池中包含了2條線程
//提交和Runnable接口的方法或者Callable(提交任務)
pool.submit( new MyRunnable()) ;
pool.submit( new MyRunnable()) ;
//pool-1-thread-2 :線程池-池數-線程類對象的描述-編號(從1開始)
//關閉線程池
pool.shutdown();
}
}
package org.westos_13;
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int x = 0 ; x < 100 ; x ++) {
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
簡單工廠模式--->靜態工廠方法模式
設計一個工廠類:
工廠類提供一些靜態方法,間接的去創建具體的對象
優點:
不需要在創建具體類的對象,而是把創建的工作交給了工廠類來創建!
弊端:如果有新的對象增加,或者某些對象的創建方式不同,就需要不斷的修改工廠類,不利於後期的維護
工廠方法模式
提供一個抽象類(抽象工廠)還需要提供一個接口(工廠接口),每一個具體的類都有對應的工廠類(實現工廠接口)
具體對象的創建工作由繼承抽象工廠的具體類實現
優點:
客戶端不需要在負責對象的創建(不需顯示創建具體對象),從而明確了各個類的職責,
如果有新的對象增加,只需要增加一個具體的類和具體的工廠類即可,不影響已有的代碼,後期維護容易,增強 了系統的擴展性
弊端:
書寫代碼量大了!
設計模式之單例模式
單例模式核心思想:某些類的對象在創建的時候 ,在系統內存始終只有一個對象!
單例模式分類:
1)餓漢式 2)懶漢式(類似於多線程環境..) 兩種分類在設計上幾乎一樣
餓漢式:
在加載那個類的時候,對象的創建工作就已經完成了!
1)定義個類,將該類的無參構造方法私有化
2)在該類的成員位置創建該類對象 並且一定要私有化,防止外界更改這個對象
3)在該類中提供靜態成員方法(返回值就是創建的那個對象),能被當前類直接調用,static修飾
懶漢式:
符合單例模式核心思想
1)自定義一個類,將無參構造私有化
2)在成員位置聲明變量
3)提供公共靜態功能,在裏面判斷的創建該類對象,返回該類對象
如果是開發中,那麽就使用餓漢式(餓漢式它不會出現問題的單例模式)
如果是面試中,那麽使用懶漢式(因為他是可能出現問題的一種單例模式)
面試題:
你使用過單例模式嗎?簡單介紹一種單例模式,請用代碼設計
面試官想問的是:使用設計單例的懶漢式,能否想到使用同步機制解決線程的安全問題..
懶漢式(延遲加載 -->懶加載)
可能會出現問題
---> 多線程的問題
--->校驗多線程安全問題的標準
1)是否是多線程環境
2)是否有共享數據
3)是否有多條語句對共享數據進行操作 (使用同步機制進行操作)
13.網絡的概念
計算機網絡:
多臺計算機通過網絡協議,實現網絡資源共享和信息傳遞!
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協議 不需要建立連接通道
.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 地址的文本表示形式;
Udp編程
1)不需要建立連接通道
2)數據大小有限制
3)不可靠連接---->傳輸速度快!
發送端的開發步驟:
1)創建發送端的Socket對象
2)創建數據,並打包
3)調用當前發送端Socket對象中的發送的方法
4)關閉資源
方法: buf - 包數據。
offset - 包數據偏移量。
length - 包數據長度。
address - 目的地址。
port - 目的端口號。
Udp編程的接收端 開發步驟:
1)創建Socket對象
2)創建一個數據報包(接收容器)
3)調用Socket對象中的接收的方法
4)解析實際傳遞的數據
5)將解析的數據(ip,數據)展示在控制臺上
6)關閉資源
註意:
接收端不要運行多次,會出現異常:
java.net.BindException: Address already in use: Cannot bind
5月30日學習內容