java筆記08

多線程&JUC

1.什么是多線程

1.什么是多線程?有了多線程,我們就可以讓程序同時做多件事情
2.多線程的作用?提高效率
3.多線程的應用場景?只要你想讓多個事情同時運行就需要用到多線程比如:軟件中的耗時操作、所有的聊天軟件、所有的服務器

2.并發和并行

并發:在同一時刻,有多個指令在單個CPU上交替執行
并行:在同一時刻,有多個指令在多個CPU上同時執行

3.多線程的實現方式

第一種實現方式:繼承Thread類的方式進行實現

package a03_多線程的實現方式.a01_第一種實現方式;public class MyThread extends Thread {@Overridepublic void run() {//書寫線程要執行代碼for (int i = 0; i < 100; i++) {System.out.println(getName() + "HelloWorld");}}
}
package a03_多線程的實現方式.a01_第一種實現方式;public class 繼承Thread類的方式進行實現 {public static void main(String[] args) {/*多線程的第一種啟動方式:繼承Thread類的方式進行實現1. 自己定義一個類繼承Thread2. 重寫run方法3. 創建子類的對象,并啟動線程*/MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("線程1");t2.setName("線程2");t1.start();t2.start();}
}

第二種實現方式:實現Runnable接口的方式進行實現

package a03_多線程的實現方式.a02_第二種實現方式;public class MyRun implements Runnable {@Overridepublic void run() {//書寫線程要執行的代碼for (int i = 0; i < 100; i++) {//獲取到當前線程的對象/*Thread t = Thread.currentThread();System.out.println(t.getName() + "HelloWorld!");/*/System.out.println(Thread.currentThread().getName() + "HelloWorld!");}}
}
package a03_多線程的實現方式.a02_第二種實現方式;public class 實現Runnable接口的方式進行實現 {public static void main(String[] args) {/** 多線程的第二種啟動方式:*   1.自己定義一個類實現Runnable接口*   2.重寫里面的run方法*   3.創建自己的類的對象*   4.創建一個Thread類的對象,并開啟線程* *///創建MyRun的對象//表示多線程要執行的任務MyRun mr = new MyRun();//創建線程對象Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);//給線程設置名字t1.setName("線程1");t2.setName("線程2");//開啟線程t1.start();t2.start();}
}

第三種實現方式:利用Callable接口和Future接口方式實現

package a03_多線程的實現方式.a03_第三種實現方式;import java.util.concurrent.Callable;public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {//求1~100之間的和int sum = 0;for (int i = 1; i <= 100; i++) {sum = sum + i;}return sum;}
}
package a03_多線程的實現方式.a03_第三種實現方式;import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class 利用Callable接口和Future接口方式實現 {public static void main(String[] args) throws ExecutionException, InterruptedException {/*多線程的第三種實現方式:特點:可以獲取到多線程運行的結果1. 創建一個類MyCallable實現Callable接口2. 重寫call(是有返回值的,表示多線程運行的結果)3. 創建MyCallable的對象(表示多線程要執行的任務)4. 創建FutureTask的對象(作用:管理多線程運行的結果)5. 創建Thread類的對象,并啟動(表示線程)*///創建MyCallable的對象(表示多線程要執行的任務)MyCallable mc = new MyCallable();//創建FutureTask的對象(作用:管理多線程運行的結果)FutureTask<Integer> ft = new FutureTask<>(mc);//創建線程的對象Thread t1 = new Thread(ft);//啟動線程t1.start();//獲取多線程運行的結果Integer result = ft.get();System.out.println(result);}
}
多線程三種實現方式對比優點                                   缺點
繼承Thread類      編程比較簡單,可以直接使用Thread類中的方法   可擴展性較差,不能再繼承其他的類
實現Runnable接口   擴展性強,實現該接口的同時還可            編程相對復雜,不能直接使用
實現Callable接口          以繼承其他的類                     Thread類中的方法

4.多線程中常見的成員方法

常用的成員方法

常見的成員方法
方法名稱                           說明
String getName()                   返回此線程的名稱
void setName(String name)          設置線程的名字(構造方法也可以設置名字)細節:1.如果我們沒有給線程設置名字,線程也是有默認的名字的格式:Thread-X(X 序號,從 0 開始的)2、如果我們要給線程設置名字,可以用 set 方法進行設置,也可以構造方法設置static Thread currentThread()      獲取當前線程的對象細節:當 JVM 虛擬機啟動之后,會自動的啟動多條線程其中有一條線程就叫做 main 線程他的作用就是去調用 main 方法,并執行里面的代碼在以前,我們寫的所有的代碼,其實都是運行在 main 線程當中static void sleep(long time)       讓線程休眠指定的時間,單位為毫秒細節:1.哪條線程執行到這個方法,那么哪條線程就會在這里停留對應的時間2.方法的參數:就表示睡眠的時間,單位毫秒1 秒 = 1000 毫秒3.當時間到了之后,線程會自動的醒來,繼續執行下面的其他代碼setPriority(int newPriority)       設置線程的優先級
final int getPriority()            獲取線程的優先級
final void setDaemon(boolean on)   設置為守護線程
public static void yield()     出讓線程 / 禮讓線程
public static void join()          插入線程 / 插隊線程
package a04_多線程中常見的成員方法;public class MyThread extends Thread {public MyThread() {}public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "@" + i);}}
}
package a04_多線程中常見的成員方法;public class a01_常用的成員方法 {public static void main(String[] args) throws InterruptedException {//1.創建線程的對象MyThread t1 = new MyThread("飛機");MyThread t2 = new MyThread("坦克");//2.開啟線程t1.start();t2.start();//哪條線程執行到這個方法,此時獲取的就是哪條線程的對象Thread t = Thread.currentThread();String name = t.getName();System.out.println(name);//mainSystem.out.println("11111111111");Thread.sleep(5000);System.out.println("22222222222");}
}

線程的優先級

搶占式調度:隨機
方法名稱                       說明
setPriority(int newPriority)   設置線程的優先級
final int getPriority()        獲取線程的優先級
package a04_多線程中常見的成員方法.a02_線程的優先級;public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "---" + i);}}
}
package a04_多線程中常見的成員方法.a02_線程的優先級;public class Test {public static void main(String[] args) {//創建線程要執行的參數對象MyRunnable mr = new MyRunnable();//創建線程對象Thread t1 = new Thread(mr, "飛機");Thread t2 = new Thread(mr, "坦克");//優先級默認為5t1.setPriority(1);t2.setPriority(10);t1.start();t2.start();}
}

守護線程

final void setDaemon(boolean on)  設置為守護線程
package a04_多線程中常見的成員方法.a03_守護線程;public class MyThread1 extends Thread{@Overridepublic void run() {for (int i = 1; i <= 10; i++) {System.out.println(getName() + "@" + i);}}
}
package a04_多線程中常見的成員方法.a03_守護線程;public class MyThread2 extends Thread{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(getName() + "@" + i);}}
}
package a04_多線程中常見的成員方法.a03_守護線程;public class Test {public static void main(String[] args) {/*final void setDaemon(boolean on)  設置為守護線程細節:當其他的非守護線程執行完畢之后,守護線程會陸續結束通俗易懂:當女神線程結束了,那么備胎也沒有存在的必要了*/MyThread1 t1 = new MyThread1();MyThread2 t2 = new MyThread2();t1.setName("女神");t2.setName("備胎");//把第二個線程設置為守護線程(備胎線程)t2.setDaemon(true);t1.start();t2.start();}
}

禮讓線程

package a04_多線程中常見的成員方法.a04_禮讓線程;public class MyThread extends Thread{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(getName() + "@" + i);//表示出讓當前CPU的執行權Thread.yield();}}
}
package a04_多線程中常見的成員方法.a04_禮讓線程;public class Test {public static void main(String[] args) {/*public static void yield()  出讓線程/禮讓線程*/MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("飛機");t2.setName("坦克");t1.start();t2.start();}
}

插入線程

package a04_多線程中常見的成員方法.a05_插入線程;public class MyThread extends Thread{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(getName() + "@" + i);}}
}
package a04_多線程中常見的成員方法.a05_插入線程;public class Test {public static void main(String[] args) throws InterruptedException {/*public final void join() 插入線程/插隊線程*/MyThread t = new MyThread();t.setName("土豆");t.start();//表示把t這個線程,插入到當前線程之前。//t:土豆//當前線程: main線程t.join();//執行在main線程當中的for (int i = 0; i < 10; i++) {System.out.println("main線程" + i);}}
}

5.線程的生命周期

線程的生命周期
新建:創建線程對象
就緒:有執行資格,沒有執行權,不停的搶 CPU ,通過 start() 從新建進入就緒
運行:有執行資格,有執行權,運行代碼 ,搶到 CPU 的執行權從就緒進入運行,其他線程搶走 CPU 的執行權從運行回到就緒
阻塞:沒有執行資格,沒有執行權,等著 ,通過 sleep() 或者其他阻塞式方法從運行進入阻塞,sleep() 方法時間到或其他阻塞方式結束從阻塞進入就緒
死亡:run() 執行完畢,線程死亡,變成垃圾

6.線程的安全問題

package a06_線程的安全問題;public class MyThread extends Thread {//表示這個類所有的對象,都共享ticket數據static int ticket = 0;//0 ~ 99@Overridepublic void run() {while (true) {if (ticket < 100) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}ticket++;System.out.println(getName() + "正在賣第" + ticket + "張票!!!");} else {break;}}}
}
package a06_線程的安全問題;public class Test {public static void main(String[] args) {
//        需求:某電影院目前正在上映國產大片,共有 100 張票,而它有 3 個窗口賣票,請設計一個程序模擬該電影院賣票//創建線程對象MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();//起名字t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");//開啟線程t1.start();t2.start();t3.start();}
}

7.同步代碼塊

同步代碼塊:把操作共享數據的代碼鎖起來
格式:
synchronized (鎖){操作共享數據的代碼
}特點 1:鎖默認打開,有一個線程進去了,鎖自動關閉
特點 2:里面的代碼全部執行完畢,線程出來,鎖自動打開
package a07_同步代碼塊;public class MyThread extends Thread {//表示這個類所有的對象,都共享ticket數據static int ticket = 0;//0 ~ 99//鎖對象,一定要是唯一的 一般寫MyThread.classstatic Object obj = new Object();@Overridepublic void run() {while (true) {
//        同步代碼塊:把操作共享數據的代碼鎖起來
//        格式:
//        synchronized (鎖){
//            操作共享數據的代碼
//        }//        特點 1:鎖默認打開,有一個線程進去了,鎖自動關閉
//        特點 2:里面的代碼全部執行完畢,線程出來,鎖自動打開synchronized (obj) {if (ticket < 100) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}ticket++;System.out.println(getName() + "正在賣第" + ticket + "張票!!!");} else {break;}}}}
}
package a07_同步代碼塊;import a06_線程的安全問題.MyThread;public class Test {public static void main(String[] args) {
//        需求:某電影院目前正在上映國產大片,共有 100 張票,而它有 3 個窗口賣票,請設計一個程序模擬該電影院賣票//創建線程對象a06_線程的安全問題.MyThread t1 = new a06_線程的安全問題.MyThread();a06_線程的安全問題.MyThread t2 = new a06_線程的安全問題.MyThread();a06_線程的安全問題.MyThread t3 = new MyThread();//起名字t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");//開啟線程t1.start();t2.start();t3.start();}
}

8.同步方法

package a08_同步方法;public class MyRunnable implements Runnable {int ticket = 0;@Overridepublic void run() {//1.循環while (true) {//2.同步代碼塊(同步方法)if (method()) break;}}private synchronized boolean method() {//3.判斷共享數據是否到了末尾,如果到了末尾if (ticket == 100) {return true;} else {//4.判斷共享數據是否到了末尾,如果沒有到末尾try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}ticket++;System.out.println(Thread.currentThread().getName() + "在賣第" + ticket + "張票!!!");}return false;}
}
package a08_同步方法;public class Test {public static void main(String[] args) {
//        需求:
//        某電影院目前正在上映國產大片,共有 100 張票,而它有 3 個窗口賣票,請設計一個程序模擬該電影院賣票
//        利用同步方法完成
//        技巧:同步代碼塊提取成方法MyRunnable mr = new MyRunnable();Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);Thread t3 = new Thread(mr);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

9.lock鎖

Lock 鎖
雖然我們可以理解同步代碼塊和同步方法的鎖對象問題,但是我們并沒有直接看到在哪里加上了鎖,在哪里釋放了鎖,為了更清晰的表達如何加鎖和釋放鎖,JDK5 以后提供了一個新的鎖對象 Lock。
Lock 實現提供比使用 synchronized 方法和語句可以獲得更廣泛的鎖定操作。Lock 中提供了獲得鎖和釋放鎖的方法:
void lock ():獲得鎖
void unlock ():釋放鎖 (手動上鎖、手動釋放鎖 )
Lock 是接口不能直接實例化,這里采用它的實現類 ReentrantLock 來實例化。
java.util.concurrent.locks.ReentrantLock 的構造方法:ReentrantLock ():創建一個 ReentrantLock 的實例
package a09_lock鎖;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MyThread extends Thread {static int ticket = 0;static Lock lock = new ReentrantLock();@Overridepublic void run() {//1.循環while (true) {//2.同步代碼塊
//            synchronized (MyThread.class) {//        Lock 鎖lock.lock();try {//3.判斷if (ticket == 100) {break;} else {Thread.sleep(10);ticket++;System.out.println(getName() + "正在賣第" + ticket + "張票!!!");}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}//            }}}
}
package a09_lock鎖;public class Test {public static void main(String[] args) {
//        需求:某電影院目前正在上映國產大片,共有 100 張票,而它有 3 個窗口賣票,請設計一個程序模擬該電影院賣票
//             用JDK5的lock實現MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

10.死鎖

package a10_死鎖;public class MyThread extends Thread{static Object objA = new Object();static Object objB = new Object();//    死鎖是一個錯誤@Overridepublic void run() {//1.循環while(true){if("線程A".equals(getName())){synchronized (objA){System.out.println("線程A拿到了A鎖,準備拿B鎖");synchronized (objB){System.out.println("線程A拿到了B鎖,順利執行完一輪");}}}else if("線程B".equals(getName())){if("線程B".equals(getName())){synchronized (objB){System.out.println("線程B拿到了B鎖,準備拿A鎖");synchronized (objA){System.out.println("線程B拿到了A鎖,順利執行完一輪");}}}}}}
}
package a10_死鎖;public class Test {public static void main(String[] args) {
//        需求:死鎖MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("線程A");t2.setName("線程B");t1.start();t2.start();}
}

11.等待喚醒機制

思路分析

生產者和消費者(等待喚醒機制)消費者操作:
1.判斷桌子上是否有食物
2.如果沒有就等待
3.如果有就開吃
4.吃完之后,喚醒廚師繼續做生產者操作:
1.判斷桌子上是否有食物
2.有:等待
3.沒有:制作食物
4.把食物放在桌子上
5.叫醒等待的消費者開吃

代碼實現

package a11_等待喚醒機制.a02_代碼實現;public class Desk {//作用:控制生產者和消費者的執行//是否有面條  0:沒有面條 1:有面條public static int foodFlag = 0;//總個數public static int count = 10;//鎖對象public static Object lock = new Object();
}
package a11_等待喚醒機制.a02_代碼實現;public class Cook extends Thread {/** 1. 循環* 2. 同步代碼塊* 3. 判斷共享數據是否到了末尾(到了末尾)* 4. 判斷共享數據是否到了末尾(沒有到末尾,執行核心邏輯)*/@Overridepublic void run() {while (true) {synchronized (Desk.lock) {if (Desk.count == 0) {break;} else {//判斷桌子上是否有食物if (Desk.foodFlag == 1) {//如果有,就等待try {Desk.lock.wait();} catch (InterruptedException e) {e.printStackTrace();}} else {//如果沒有,就制作食物System.out.println("廚師做了一碗面條");//修改桌子上的食物狀態Desk.foodFlag = 1;//叫醒等待的消費者開吃Desk.lock.notifyAll();}}}}}
}
package a11_等待喚醒機制.a02_代碼實現;public class Foodie extends Thread {@Overridepublic void run() {/** 1. 循環* 2. 同步代碼塊* 3. 判斷共享數據是否到了末尾(到了末尾)* 4. 判斷共享數據是否到了末尾(沒有到末尾,執行核心邏輯)*/while (true) {synchronized (Desk.lock) {if (Desk.count == 0) {break;} else {//先判斷桌子上是否有面條if (Desk.foodFlag == 0) {//如果沒有,就等待try {Desk.lock.wait();//讓當前線程跟鎖進行綁定} catch (InterruptedException e) {e.printStackTrace();}} else {//把吃的總數-1Desk.count--;//如果有,就開吃System.out.println("吃貨在吃面條,還能再吃" + Desk.count + "碗!!!");//吃完之后,喚醒廚師繼續做Desk.lock.notifyAll();//修改桌子的狀態Desk.foodFlag = 0;}}}}}
}
package a11_等待喚醒機制.a02_代碼實現;public class Test {public static void main(String[] args) {/*需求:完成生產者和消費者(等待喚醒機制)的代碼實現線程輪流交替執行的效果*///創建線程的對象Cook c = new Cook();Foodie f = new Foodie();//給線程設置名字c.setName("廚師");f.setName("吃貨");//開啟線程c.start();f.start();}
}

阻塞隊列實現等待喚醒機制

package a11_等待喚醒機制.a03_阻塞隊列實現等待喚醒機制;import java.util.concurrent.ArrayBlockingQueue;public class Cook extends Thread {ArrayBlockingQueue<String> queue;public Cook(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while (true) {//不斷的把面條放到阻塞隊列當中try {queue.put("面條");System.out.println("廚師放了一碗面條");} catch (InterruptedException e) {e.printStackTrace();}}}
}
package a11_等待喚醒機制.a03_阻塞隊列實現等待喚醒機制;import java.util.concurrent.ArrayBlockingQueue;public class Foodie extends Thread{ArrayBlockingQueue<String> queue;public Foodie(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while(true){//不斷從阻塞隊列中獲取面條try {String food = queue.take();System.out.println(food);} catch (InterruptedException e) {e.printStackTrace();}}}
}
package a11_等待喚醒機制.a03_阻塞隊列實現等待喚醒機制;import java.util.concurrent.ArrayBlockingQueue;public class Test {public static void main(String[] args) {
//        阻塞隊列的繼承結構
//        接口:
//        Iterable
//        Collection
//        Queue
//        BlockingQueue//        實現類:
//        ArrayBlockingQueue:底層是數組,有界
//        LinkedBlockingQueue:底層是鏈表,無界,但不是真正的無界,最大為 int 的最大值/*需求:利用阻塞隊列完成生產者和消費者(等待喚醒機制)的代碼細節:生產者和消費者必須使用同一個阻塞隊列*///1.創建阻塞隊列的對象ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);//2.創建線程的對象,并把阻塞隊列傳遞過去Cook c = new Cook(queue);Foodie f = new Foodie(queue);//3.開啟線程c.start();f.start();}
}

12.多線程的6種狀態

線程的狀態
新建狀態(NEW):創建線程對象
就緒狀態(RUNNABLE):start方法
阻塞狀態(BLOCKED):無法獲得鎖對象
等待狀態(WAITING):wait方法
計時等待(TIMED_WAITING):sleep方法
結束狀態(TERMINATED):全部代碼運行完畢

13.綜合練習

搶紅包

package a13_綜合練習.a01_搶紅包;import java.util.Random;public class MyThread extends Thread {//共享數據//100塊,分成了3個包static double money = 100;static int count = 3;//最小的中獎金額static final double MIN = 0.01;@Overridepublic void run() {//同步代碼塊synchronized (MyThread.class) {if (count == 0) {//判斷,共享數據是否到了末尾(已經到末尾)System.out.println(getName() + "沒有搶到紅包!");} else {//判斷,共享數據是否到了末尾(沒有到末尾)//定義一個變量,表示中獎的金額double prize = 0;if (count == 1) {//表示此時是最后一個紅包//就無需隨機,剩余所有的錢都是中獎金額prize = money;} else {//表示第一次,第二次(隨機)Random r = new Random();//100元  3個包//第一個紅包:99.98//100 - (3-1) * 0.01double bounds = money - (count - 1) * MIN;prize = r.nextDouble(bounds);if (prize < MIN) {prize = MIN;}}//從money當中,去掉當前中獎的金額money = money - prize;//紅包的個數-1count--;//本次紅包的信息進行打印System.out.println(getName() + "搶到了" + prize + "元");}}}
}
package a13_綜合練習.a01_搶紅包;public class Test {public static void main(String[] args) {/*微信中的搶紅包也用到了多線程。假設:100塊,分成了3個包,現在有5個人去搶。其中,紅包是共享數據。5個人是5條線程。打印結果如下:XXX搶到了XXX元XXX搶到了XXX元XXX搶到了XXX元XXX沒搶到XXX沒搶到*///創建線程的對象MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();MyThread t4 = new MyThread();MyThread t5 = new MyThread();//給線程設置名字t1.setName("小A");t2.setName("小QQ");t3.setName("小哈哈");t4.setName("小濤濤");t5.setName("小丹丹");//啟動線程t1.start();t2.start();t3.start();t4.start();t5.start();}
}

抽獎

package a13_綜合練習.a02_抽獎;import java.util.ArrayList;
import java.util.Collections;public class MyThread extends Thread{ArrayList<Integer> list;public MyThread(ArrayList<Integer> list) {this.list = list;}@Overridepublic void run() {//1.循環//2.同步代碼塊//3.判斷//4.判斷while (true) {synchronized (MyThread.class) {if (list.size() == 0) {break;} else {//繼續抽獎Collections.shuffle(list);int prize = list.remove(0);System.out.println(getName() + "又產生了一個" + prize + "元大獎");}}try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
package a13_綜合練習.a02_抽獎;import java.util.ArrayList;
import java.util.Collections;public class Test {public static void main(String[] args) {/*有一個抽獎池,該抽獎池中存放了獎勵的金額,該抽獎池中的獎項為 {10,5,20,50,100,200,500,800,2,80,300,700};創建兩個抽獎箱(線程)設置線程名稱分別為"抽獎箱1","抽獎箱2"隨機從抽獎池中獲取獎項元素并打印在控制臺,格式如下:每次抽出一個獎項就打印一個(隨機)抽獎箱1 又產生了一個 10 元大獎抽獎箱1 又產生了一個 100 元大獎抽獎箱1 又產生了一個 200 元大獎抽獎箱1 又產生了一個 800 元大獎抽獎箱2 又產生了一個 700 元大獎......*///創建獎池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 10,5,20,50,100,200,500,800,2,80,300,700);//創建線程MyThread t1 = new MyThread(list);MyThread t2 = new MyThread(list);//設置名字t1.setName("抽獎箱1");t2.setName("抽獎箱2");//啟動線程t1.start();t2.start();}
}

多線程統計并求最大值解法一

package a13_綜合練習.a03_多線程統計并求最大值.a01_解法一;import java.util.ArrayList;
import java.util.Collections;public class MyThread extends Thread{ArrayList<Integer> list;public MyThread(ArrayList<Integer> list) {this.list = list;}//線程一static ArrayList<Integer> list1 = new ArrayList<>();//線程二static ArrayList<Integer> list2 = new ArrayList<>();@Overridepublic void run() {while (true) {synchronized (MyThread.class) {if (list.size() == 0) {if("抽獎箱1".equals(getName())){System.out.println("抽獎箱1" + list1);}else {System.out.println("抽獎箱2" + list2);}break;} else {//繼續抽獎Collections.shuffle(list);int prize = list.remove(0);if("抽獎箱1".equals(getName())){list1.add(prize);}else {list2.add(prize);}}}try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
package a13_綜合練習.a03_多線程統計并求最大值.a01_解法一;import java.util.ArrayList;
import java.util.Collections;public class Test {public static void main(String[] args) {
//        有一個抽獎池,該抽獎池中存放了獎勵的金額,該抽獎池中的獎項為 {10,5,20,50,100,200,500,800,2,80,300,700}
//        創建兩個抽獎箱(線程)設置線程名稱分別為"抽獎箱1","抽獎箱2"
//        隨機從抽獎池中獲取獎項元素并打印在控制臺上,格式如下:
//        每次抽的過程中,不打印,抽完時一次性打印(隨機)
//        在此次抽獎過程中,抽獎箱1總共產了6個獎項。
//              分別為: 10,20,100,500,2,300最高獎項為300元,總計額為932元
//        在此次抽獎過程中,抽獎箱2總共產了6個獎項。
//              分別為: 5,50,200,800,80,700最高獎項為800元,總計額為1835元//創建獎池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 10,5,20,50,100,200,500,800,2,80,300,700);//創建線程MyThread t1 = new MyThread(list);MyThread t2 = new MyThread(list);//設置名字t1.setName("抽獎箱1");t2.setName("抽獎箱2");//啟動線程t1.start();t2.start();}
}

多線程統計并求最大值解法二(線程棧)

package a13_綜合練習.a03_多線程統計并求最大值.a02_解法二_線程棧;import java.util.ArrayList;
import java.util.Collections;public class MyThread extends Thread {ArrayList<Integer> list;public MyThread(ArrayList<Integer> list) {this.list = list;}@Overridepublic void run() {ArrayList<Integer> boxList = new ArrayList<>();while (true) {synchronized (MyThread.class) {if (list.size() == 0) {System.out.println(getName() + boxList);break;} else {//繼續抽獎Collections.shuffle(list);int prize = list.remove(0);boxList.add(prize);}}try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
package a13_綜合練習.a03_多線程統計并求最大值.a02_解法二_線程棧;import java.util.ArrayList;
import java.util.Collections;public class Test {public static void main(String[] args) {
//        有一個抽獎池,該抽獎池中存放了獎勵的金額,該抽獎池中的獎項為 {10,5,20,50,100,200,500,800,2,80,300,700}
//        創建兩個抽獎箱(線程)設置線程名稱分別為"抽獎箱1","抽獎箱2"
//        隨機從抽獎池中獲取獎項元素并打印在控制臺上,格式如下:
//        每次抽的過程中,不打印,抽完時一次性打印(隨機)
//        在此次抽獎過程中,抽獎箱1總共產了6個獎項。
//              分別為: 10,20,100,500,2,300最高獎項為300元,總計額為932元
//        在此次抽獎過程中,抽獎箱2總共產了6個獎項。
//              分別為: 5,50,200,800,80,700最高獎項為800元,總計額為1835元//創建獎池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 10,5,20,50,100,200,500,800,2,80,300,700);//創建線程MyThread t1 = new MyThread(list);MyThread t2 = new MyThread(list);//設置名字t1.setName("抽獎箱1");t2.setName("抽獎箱2");//啟動線程t1.start();t2.start();}
}

多線程之間的比較

package a13_綜合練習.a04_多線程之間的比較;import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Callable;public class MyCallable implements Callable<Integer> {ArrayList<Integer> list;public MyCallable(ArrayList<Integer> list) {this.list = list;}@Overridepublic Integer call() throws Exception {ArrayList<Integer> boxList = new ArrayList<>();while (true) {synchronized (MyCallable.class) {if (list.size() == 0) {System.out.println(Thread.currentThread().getName() + boxList);break;} else {//繼續抽獎Collections.shuffle(list);int prize = list.remove(0);boxList.add(prize);}}Thread.sleep(10);}//把集合中的最大值返回if(boxList.size() == 0){return null;}else{return Collections.max(boxList);}}
}
package a13_綜合練習.a04_多線程之間的比較;import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {/*有一個抽獎池,該抽獎池中存放了獎勵的金額,該抽獎池中的獎項為 {10,5,20,50,100,200,500,800,2,80,300,700};創建兩個抽獎箱(線程)設置線程名稱分別為 "抽獎箱1", "抽獎箱2"隨機從抽獎池中獲取獎項元素并打印在控制臺上,格式如下:在此次抽獎過程中,抽獎箱1總共產了6個獎項,分別為: 10,20,100,500,2,300最高獎項為300元,總計額為932元在此次抽獎過程中,抽獎箱2總共產了6個獎項,分別為: 5,50,200,800,80,700最高獎項為800元,總計額為1835元在此次抽獎過程中,抽獎箱2中產生了最大獎項,該獎項金額為800元以上打印效果只是數據模擬,實際代碼運行的效果會有差異*///創建獎池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);//創建多線程要運行的參數對象MyCallable mc = new MyCallable(list);//創建多線程運行結果的管理者對象//線程一FutureTask<Integer> ft1 = new FutureTask<>(mc);//線程二FutureTask<Integer> ft2 = new FutureTask<>(mc);//創建線程對象Thread t1 = new Thread(ft1);Thread t2 = new Thread(ft2);//設置名字t1.setName("抽獎箱1");t2.setName("抽獎箱2");//開啟線程t1.start();t2.start();Integer max1 = ft1.get();Integer max2 = ft2.get();System.out.println(max1);System.out.println(max2);}
}

14.線程池

以前寫多線程的弊端
弊端1:用到線程的時候就創建
弊端2:用完之后線程消失線程池主要核心原理
1.創建一個池子,池子中是空的
2.提交任務時,池子會創建新的線程對象,任務執行完畢,線程歸還給池子下回再次提交任務時,不需要創建新的線程,直接復用已有的線程即可
3.但是如果提交任務時,池子中沒有空閑線程,也無法創建新的線程,任務就會排隊等待線程池代碼實現
Executors:線程池的工具類通過調用方法返回不同類型的線程池對象。方法名稱                                                           說明
public static ExecutorService newCachedThreadPool()                創建一個沒有上限的線程池
public static ExecutorService newFixedThreadPool(int nThreads) 創建有上限的線程池
package a14_線程池;public class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "---" + i);}}
}
//1.獲取線程池對象
ExecutorService pool1 = Executors.newCachedThreadPool();//2.提交任務
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());//3.銷毀線程池
pool1.shutdown();

15.自定義線程池

自定義線程池小結創建一個空的池子有任務提交時,線程池會創建線程去執行任務,執行完畢歸還線程不斷的提交任務,會有以下三個臨界點:當核心線程滿時,再提交任務就會排隊當核心線程滿,隊伍滿時,會創建臨時線程當核心線程滿,隊伍滿,臨時線程滿時,會觸發任務拒絕策略自定義線程池 (任務拒絕策略)
任務拒絕策略                             說明
ThreadPoolExecutor.AbortPolicy         默認策略:丟棄任務并拋出 RejectedExecutionException 異常
ThreadPoolExecutor.DiscardPolicy           丟棄任務,但是不拋出異常 這是不推薦的做法
ThreadPoolExecutor.DiscardOldestPolicy 拋棄隊列中等待最久的任務 然后把當前任務加入隊列中
ThreadPoolExecutor.CallerRunsPolicy        調用任務的 run () 方法繞過線程池直接執行
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
(核心線程數量,最大線程數量,空閑線程最大存活時間,任務隊列,創建線程工廠,任務的拒絕策略);參數一:核心線程數量           不能小于0
參數二:最大線程數             不能小于等于0,最大數量 >= 核心線程數量
參數三:空閑線程最大存活時間     不能小于0
參數四:時間單位               用TimeUnit指定
參數五:任務隊列               不能為null
參數六:創建線程工廠           不能為null
參數七:任務的拒絕策略          不能為null
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, //核心線程數量,能小于06, //最大線程數,不能小于0,最大數量 >= 核心線程數量60, //空閑線程最大存活時間TimeUnit.SECONDS, //時間單位new ArrayBlockingQueue<>(3), //任務隊列Executors.defaultThreadFactory(), //創建線程工廠new ThreadPoolExecutor.AbortPolicy() //任務的拒絕策略
);

16.最大并行數

package a16_最大并行數;public class Test {public static void main(String[] args) {//向Java虛擬機返回可用處理器的數目int count = Runtime.getRuntime().availableProcessors();System.out.println(count);}
}

17.線程池多大合適

線程池多大合適呢?
CPU密集型運算:最大并行數 + 1
I/O密集型運算:最大并行數 * 期望CPU利用率 * (總時間(CPU計算時間 + 等待時間)/CPU計算時間)
舉例:從本地文件中,讀取兩個數據,并進行相加
操作一:讀取兩個數據(1 秒鐘)
操作二:相加(1 秒鐘)
4核8線程:8 * 100% * ( 100% / 50%)
網絡編程

1.初識網絡編程

什么是網絡編程?
在網絡通信協議下,不同計算機上運行的程序,進行的數據傳輸。
應用場景:即時通信、網游對戰、金融證券、國際貿易、郵件、等等。不管是什么場景,都是計算機跟計算機之間通過網絡進行數據傳輸。
Java 中可以使用java.net包下的技術輕松開發出常見的網絡應用程序。
常見的軟件架構:BS、CSBS/CS 架構的優缺點
應用軟件的架構分類
BS01:不需要開發客戶端,只需要開發服務端02:用戶不需要下載,打開瀏覽器就能使用03:如果應用過大,用戶體驗受到影響
CS01:畫面可以做的非常精美,用戶體驗好02:需要開發客戶端,也需要開發服務端03:用戶需要下載和更新的時候太麻煩

2.網絡編程三要素

網絡編程三要素
IP設備在網絡中的地址,是唯一的標識
端口號應用程序在設備中唯一的標識
協議數據在網絡中傳輸的規則,常見的協議有 UDP、TCP、http、https、ftp

IP

1.Ip 的作用設備在網絡中的地址,是唯一的標識
2.IPv4 有什么特點目前的主流方案最多只有 2^32 次方個 ip,目前已經用完了
3.IPv6 有什么特點為了解決 IPv4 不夠用而出現的最多有 2^128 次方個 ip可以為地球上的每一粒沙子都設定 ip

ipv4的一些小細節

現在如何解決IPv4不夠的問題?利用局域網IP解決IP不夠的問題
特殊的IP是什么?127.0.0.1(永遠表示本機)
常見的兩個 CMD 命令?ipconfig:查看本機IP地址ping:檢查網絡是否連通

InetAddress類的使用

static InetAddress getByName(String host) 確定主機名稱的IP地址。主機名稱可以是機器名稱,也可以是IP地址
String getHostName()  獲取此IP地址的主機名
String getHostAddress()  返回文本顯示中的IP地址字符串
package a02_網絡編程三要素.a02_IP;import java.net.InetAddress;
import java.net.UnknownHostException;public class a03_InetAddress類的使用 {public static void main(String[] args) throws UnknownHostException {//1.獲取InetAddress的對象//IP的對象 一臺電腦的對象InetAddress address = InetAddress.getByName("魏巍");System.out.println(address);String name = address.getHostName();System.out.println(name);String ip = address.getHostAddress();System.out.println(ip);//192.168.58.165}
}

3.端口號

端口號
應用程序在設備中唯一的標識端口號:由兩個字節表示的整數,取值范圍:0~65535
其中 0~1023 之間的端口號用于一些知名的網絡服務或者應用
我們自己使用 1024 以上的端口號就可以了注意:一個端口號只能被一個應用程序使用

4.協議

UDP協議和TCP協議簡介

協議:計算機網絡中,連接和通信的規則被稱為網絡通信協議
UDP 協議
用戶數據報協議 (User Datagram Protocol)
UDP 是面向無連接通信協議
速度快,有大小限制一次最多發送 64K,數據不安全,易丟失數據
TCP 協議
傳輸控制協議 TCP (Transmission Control Protocol)
TCP 協議是面向連接的通信協議
速度慢,沒有大小限制,數據安全

UDP協議

UDP 通信程序(發送數據)
創建發送端的 DatagramSocket 對象
數據打包(DatagramPacket)
發送數據
釋放資源
package a02_網絡編程三要素.a04_協議.a02_UDP協議;import java.io.IOException;
import java.net.*;public class a01_發送數據 {public static void main(String[] args) throws IOException {//發送數據//1.創建DatagramSocket對象(快遞公司)//細節://綁定端口,以后我們就是通過這個端口往外發送//空參:所有可用的端口中隨機一個進行使用//有參:指定端口號進行綁定DatagramSocket ds = new DatagramSocket();//2.打包數據String str = "你好啊!!!";byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);//3.發送數據ds.send(dp);//4.釋放資源ds.close();}
}
UDP 通信程序(接收數據)
創建接收端的 DatagramSocket 對象
接收打包好的數據
解析數據包
釋放資源
package a02_網絡編程三要素.a04_協議.a02_UDP協議;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class a02_接收數據 {public static void main(String[] args) throws IOException {//接收數據//1.創建DatagramSocket對象(快遞公司)//細節://在接收的時候,一定要綁定端口//而且綁定的端口一定要跟發送的端口保持一致DatagramSocket ds = new DatagramSocket(10086);//2.接收數據包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);//該方法是阻塞的//程序執行到這一步的時候,會在這里死等//等發送端發送消息System.out.println(11111);ds.receive(dp);System.out.println(22222);//3.解析數據包byte[] data = dp.getData();int len = dp.getLength();InetAddress address = dp.getAddress();int port = dp.getPort();System.out.println("接收到數據" + new String(data, 0,len));System.out.println("該數據是從" + address + "這臺電腦中的" + port + "這個端口發出的");//4.釋放資源ds.close();}
}

單播、組播、廣播

UDP 的三種通信方式(代碼實現)
單播以前的代碼就是單播
組播組播地址:224.0.0.0 ~ 239.255.255.255其中 224.0.0.0 ~ 224.0.0.255 為預留的組播地址
廣播廣播地址:255.255.255.255
package a02_網絡編程三要素.a04_協議.a04_單播_組播_廣播;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;public class SendMessage {public static void main(String[] args) throws IOException {/*組播發送端代碼*///創建MulticastSocket對象MulticastSocket ms = new MulticastSocket();// 創建DatagramPacket對象String s = "你好,你好!";byte[] bytes = s.getBytes();
//        組播InetAddress address = InetAddress.getByName("224.0.0.1");
//        廣播
//        InetAddress address = InetAddress.getByName("255.255.255.255");int port = 10000;DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, port);// 調用MulticastSocket發送數據方法發送數據ms.send(datagramPacket);// 釋放資源ms.close();}
}
package a02_網絡編程三要素.a04_協議.a04_單播_組播_廣播;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;public class ReceiveMessage1 {public static void main(String[] args) throws IOException {/*組播接收端代碼*///1.創建MulticastSocket對象MulticastSocket ms = new MulticastSocket(10000);//2.將當前本機,添加到224.0.0.1的這一組當中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);//3.創建DatagramPacket數據包對象byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);//4.接收數據ms.receive(dp);//5.解析數據byte[] data = dp.getData();int len = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip為:" + ip + ",主機名為:" + name + "的人,發送了數據:" + new String(data, 0,len));//6.釋放資源ms.close();}
}
package a02_網絡編程三要素.a04_協議.a04_單播_組播_廣播;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;public class ReceiveMessage2 {public static void main(String[] args) throws IOException {/*組播接收端代碼*///1.創建MulticastSocket對象MulticastSocket ms = new MulticastSocket(10000);//2.將當前本機,添加到224.0.0.1的這一組當中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);//3.創建DatagramPacket數據包對象byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);//4.接收數據ms.receive(dp);//5.解析數據byte[] data = dp.getData();int len = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip為:" + ip + ",主機名為:" + name + "的人,發送了數據:" + new String(data, 0,len));//6.釋放資源ms.close();}
}
package a02_網絡編程三要素.a04_協議.a04_單播_組播_廣播;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;public class ReceiveMessage3 {public static void main(String[] args) throws IOException {/*組播接收端代碼*///1.創建MulticastSocket對象MulticastSocket ms = new MulticastSocket(10000);//2.將當前本機,添加到224.0.0.1的這一組當中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);//3.創建DatagramPacket數據包對象byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);//4.接收數據ms.receive(dp);//5.解析數據byte[] data = dp.getData();int len = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip為:" + ip + ",主機名為:" + name + "的人,發送了數據:" + new String(data, 0,len));//6.釋放資源ms.close();}
}

TCP協議

TCP 通信程序TCP 通信協議是一種可靠的網絡協議,它在通信的兩端各建立一個 Socket 對象通信之前要保證連接已經建立通過 Socket 產生 IO 流來進行網絡通信客戶端
1.創建客戶端的 Socket 對象 (Socket) 與指定服務端連接
Socket (String host, int port)
2.獲取輸出流,寫數據
OutputStream getOutputStream ()
3.釋放資源
void close ()服務器端
1.創建服務器端的 Socket 對象 (ServerSocket)
ServerSocket (int port)
2.監聽客戶端連接,返回一個 Socket 對象
java.net.Socket accept ()
3.獲取輸入流,讀數據,并把數據顯示在控制臺
InputStream getInputStream ()
4.釋放資源
void close ()
package a02_網絡編程三要素.a04_協議.a05_TCP協議;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//TCP協議,發送數據//1.創建Socket對象//細節:在創建對象的同時會連接服務端//      如果連接不上,代碼會報錯Socket socket = new Socket("127.0.0.1", 10086);//2.可以從連接通道中獲取輸出流OutputStream os = socket.getOutputStream();//寫出數據os.write("你好你好".getBytes());//3.釋放資源os.close();socket.close();}
}
package a02_網絡編程三要素.a04_協議.a05_TCP協議;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//TCP協議,接收數據//1.創建對象ServerSocketServerSocket ss = new ServerSocket(10086);//2.監聽客戶端的鏈接Socket socket = ss.accept();//3.從連接通道中獲取輸入流讀取數據
//        InputStream is = socket.getInputStream();
//        InputStreamReader isr = new InputStreamReader(is);
//        BufferedReader br = new BufferedReader(isr);BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));int b;while ((b = br.read()) != -1) {System.out.print((char) b);}//4.釋放資源socket.close();ss.close();}
}

3.三次握手和四次揮手

TCP 通信程序(三次握手)
客戶端向服務器發出連接請求,等待服務器確認
服務器向客戶端返回一個響應,告訴客戶端收到了請求
客戶端向服務器再次發出確認信息,連接建立TCP 通信程序(四次揮手)
客戶端向服務器發出取消連接請求
服務器向客戶端返回一個響應,表示收到客戶端取消請求
服務器向客戶端發出確認取消信息(服務器將最后的數據處理完畢 )
客戶端再次發送確認消息,連接取消

4.綜合練習

多發多收

package a02_網絡編程三要素.a04_協議.a07_綜合練習.a01_多發多收;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {//客戶端:多次發送數據//服務器:接收多次接收數據,并打印//1. 創建Socket對象并連接服務端Socket socket = new Socket("127.0.0.1", 10000);//2.寫出數據Scanner sc = new Scanner(System.in);OutputStream os = socket.getOutputStream();while (true) {System.out.println("請輸入您要發送的信息");String str = sc.nextLine();if("886".equals(str)){break;}os.write(str.getBytes());}//3.釋放資源socket.close();}
}
package a02_網絡編程三要素.a04_協議.a07_綜合練習.a01_多發多收;import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//客戶端:多次發送數據//服務器:接收多次接收數據,并打印//1.創建對象綁定10000端口ServerSocket ss = new ServerSocket(10000);//2.等待客戶端來連接Socket socket = ss.accept();//3.讀取數據InputStreamReader isr = new InputStreamReader(socket.getInputStream());int b;while ((b = isr.read()) != -1){System.out.print((char)b);}//4.釋放資源socket.close();ss.close();}
}

接收并反饋

package a04_綜合練習.a03_上傳文件;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//客戶端:將本地文件上傳到服務器。接收服務器的反饋。//服務器:接收客戶端上傳的文件,上傳完畢之后給出反饋。//1. 創建Socket對象,并連接服務器Socket socket = new Socket("127.0.0.1", 10086);//2.讀取本地文件中的數據,并寫到服務器當中BufferedInputStream bis = new BufferedInputStream(new FileInputStream("mysocketnet\\clientdir\\a.jpg"));BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1){bos.write(bytes, 0,len);}//往服務器寫出結束標記socket.shutdownOutput();//3.接收服務器的回寫數據BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String line = br.readLine();System.out.println(line);//4.釋放資源socket.close();}
}
package a04_綜合練習.a02_接收并反饋;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//客戶端:發送一條數據,接收服務端反饋的消息并打印//服務器:接收數據并打印,再給客戶端反饋消息//1.創建Socket對象并連接服務端Socket socket = new Socket("127.0.0.1", 10086);//2.寫出數據String str = "見到你很高興!";OutputStream os = socket.getOutputStream();os.write(str.getBytes());//寫出一個結束標記socket.shutdownOutput();//3.接收服務端回寫的數據InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);int b;while ((b = isr.read()) != -1){System.out.print((char)b);}//釋放資源socket.close();}
}

上傳文件

package a04_綜合練習.a03_上傳文件;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//客戶端:將本地文件上傳到服務器。接收服務器的反饋。//服務器:接收客戶端上傳的文件,上傳完畢之后給出反饋。//1. 創建Socket對象,并連接服務器Socket socket = new Socket("127.0.0.1", 10086);//2.讀取本地文件中的數據,并寫到服務器當中BufferedInputStream bis = new BufferedInputStream(new FileInputStream("mysocketnet\\clientdir\\a.jpg"));BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1){bos.write(bytes, 0,len);}//往服務器寫出結束標記socket.shutdownOutput();//3.接收服務器的回寫數據BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String line = br.readLine();System.out.println(line);//4.釋放資源socket.close();}
}
package a04_綜合練習.a03_上傳文件;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//客戶端:將本地文件上傳到服務器。接收服務器的反饋。//服務器:接收客戶端上傳的文件,上傳完畢之后給出反饋。//1.創建對象并綁定端口ServerSocket ss = new ServerSocket(10000);//2.等待客戶端來連接Socket socket = ss.accept();//3.讀取數據并保存到本地文件中BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet\\serverdir\\a.jpg"));int len;byte[] bytes = new byte[1024];while ((len = bis.read(bytes)) != -1){bos.write(bytes, 0,len);}//4.回寫數據BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上傳成功");bw.newLine();bw.flush();//5.釋放資源socket.close();ss.close();}
}

文件名重復

String name = UUID.randomUUID().toString().replace("-", "");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet\\serverdir\\name.jpg"));

多線程版的服務端

package a04_TCP綜合練習.a05_多線程版的服務端;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//客戶端:將本地文件上傳到服務器。接收服務器的反饋。//服務器:接收客戶端上傳的文件,上傳完畢之后給出反饋。//1.創建對象并綁定端口ServerSocket ss = new ServerSocket(10000);while (true) {//2.等待客戶端來連接Socket socket = ss.accept();//開啟一條線程//一個用戶就對應服務端的一條線程new Thread(new MyRunnable(socket)).start();}}
}
package a04_TCP綜合練習.a05_多線程版的服務端;import java.io.*;
import java.net.Socket;
import java.util.UUID;public class MyRunnable implements Runnable {Socket socket;public MyRunnable(Socket socket){this.socket = socket;}@Overridepublic void run() {try {//3.讀取數據并保存到本地文件中BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());String name = UUID.randomUUID().toString().replace("-", "");BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet\\serverdir\\name.jpg"));int len;byte[] bytes = new byte[1024];while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}//4.回寫數據BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write("上傳成功");bw.newLine();bw.flush();} catch (IOException e) {e.printStackTrace();} finally {//5.釋放資源if(socket != null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
package a04_TCP綜合練習.a05_多線程版的服務端;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//客戶端:將本地文件上傳到服務器。接收服務器的反饋。//服務器:接收客戶端上傳的文件,上傳完畢之后給出反饋。//1. 創建Socket對象,并連接服務器Socket socket = new Socket("127.0.0.1", 10086);//2.讀取本地文件中的數據,并寫到服務器當中BufferedInputStream bis = new BufferedInputStream(new FileInputStream("mysocketnet\\clientdir\\a.jpg"));BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1){bos.write(bytes, 0,len);}//往服務器寫出結束標記socket.shutdownOutput();//3.接收服務器的回寫數據BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String line = br.readLine();System.out.println(line);//4.釋放資源socket.close();}
}

線程池版的服務端

package a04_TCP綜合練習.a06_線程池版的服務端;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class Server {public static void main(String[] args) throws IOException {//客戶端:將本地文件上傳到服務器。接收服務器的反饋。//服務器:接收客戶端上傳的文件,上傳完畢之后給出反饋。//創建線程池對象ThreadPoolExecutor pool = new ThreadPoolExecutor(3,//核心線程數量16,//線程池總大小60,//空閑時間TimeUnit.SECONDS,//空閑時間(單位)new ArrayBlockingQueue<>(2),//隊列Executors.defaultThreadFactory(),//線程工廠,讓線程池如何創建線程對象new ThreadPoolExecutor.AbortPolicy()//阻塞隊列);//1.創建對象并綁定端口ServerSocket ss = new ServerSocket(10000);while (true) {//2.等待客戶端來連接Socket socket = ss.accept();//開啟一條線程//一個用戶就對應服務端的一條線程
//            new Thread(new MyRunnable(socket)).start();pool.submit(new MyRunnable(socket));}}
}
反射

1.概述

什么是反射?反射允許對成員變量,成員方法和構造方法的信息進行編程訪問
獲取               解剖
獲取 class 對象
字段(成員變量)     獲取修飾符   獲取名字    獲取類型    賦值 / 獲取值
構造方法           獲取修飾符   獲取名字    獲取形參    創建對象
成員方法           獲取修飾符   獲取名字    獲取形參    獲取返回值  拋出的異常   獲取注解    運行方法

2.獲取class對象的三種方式

package a02_獲取class對象的三種方式;public class Test {public static void main(String[] args) throws ClassNotFoundException {/** 獲取class對象的三種方式:*  1. Class.forName("全類名");*  2. 類名.class*  3. 對象.getClass();*///1. 第一種方式//全類名 : 包名 + 類名//最為常用的Class clazz1 = Class.forName("a02_獲取class對象的三種方式.Student");//2. 第二種方式//一般更多的是當做參數進行傳遞Class clazz2 = Student.class;synchronized (Student.class){}//3.第三種方式//當我們已經有了這個類的對象時,才可以使用。Student s = new Student();Class clazz3 = s.getClass();System.out.println(clazz1 == clazz2);System.out.println(clazz2 == clazz3);}
}

3.反射獲取構造方法

Class類中用于獲取構造方法的方法Constructor<?>[] getConstructors()Constructor<?>[] getDeclaredConstructors()Constructor<T> getConstructor(Class<?>... parameterTypes)Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)Constructor類中用于創建對象的方法T newInstance(Object... initargs)setAccessible(boolean flag)
package a03_反射獲取構造方法;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;public class Test {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1.獲取class字節碼文件對象Class clazz = Class.forName("a03_反射獲取構造方法.Student");//2.獲取構造方法/*Constructor[] cons1 = clazz.getConstructors();for (Constructor con : cons1) {System.out.println(con);}Constructor[] cons2 = clazz.getDeclaredConstructors();for (Constructor con : cons2) {System.out.println(con);}*/Constructor con1 = clazz.getDeclaredConstructor();System.out.println(con1);Constructor con2 = clazz.getDeclaredConstructor(String.class);System.out.println(con2);Constructor con3 = clazz.getDeclaredConstructor(int.class);System.out.println(con3);Constructor con4 = clazz.getDeclaredConstructor(String.class, int.class);System.out.println(con4);int modifiers = con4.getModifiers(); // 獲取權限修飾符 返回值是數字System.out.println(modifiers);Parameter[] parameters = con4.getParameters(); // 獲取參數for (Parameter parameter : parameters) {System.out.println(parameter);}con4.setAccessible(true); //暴力反射:表示臨時取消權限校驗(原本con4是private修飾 創建不了對象)Student stu = (Student) con4.newInstance("張三", 23); //創建對象System.out.println(stu);}
}

package a03_反射獲取構造方法;public class Student {private String name;private int age;public Student() {}public Student(String name) {this.name = name;}protected Student(int age) {this.age = age;}private Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

4.反射獲取成員變量

Class類中用于獲取成員變量的方法Field[] getFields(): 返回所有公共成員變量對象的數組Field[] getDeclaredFields(): 返回所有成員變量對象的數組Field getField(String name): 返回單個公共成員變量對象Field getDeclaredField(String name): 返回單個成員變量對象Field類中用于創建對象的方法void set(Object obj, Object value): 賦值Object get(Object obj)  獲取值
package a04_反射獲取成員變量;import java.lang.reflect.Field;public class Test {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {//1.獲取class字節碼文件的對象Class clazz = Class.forName("a04_反射獲取成員變量.Student");//2.獲取成員變量Field[] fields1 = clazz.getFields(); // 公共成員變量Field[] fields2 = clazz.getDeclaredFields(); // 所有成員變量//獲取單個的成員變量Field name = clazz.getDeclaredField("name");System.out.println(name);//獲取權限修飾符int modifiers = name.getModifiers();System.out.println(modifiers);//獲取成員變量的名字String n = name.getName();System.out.println(n);//獲取成員變量的數據類型Class<?> type = name.getType();System.out.println(type);//獲取成員變量記錄的值Student s = new Student("zhangsan", 23, "男");name.setAccessible(true);String value = (String) name.get(s);System.out.println(value);//修改對象里面記錄的值name.set(s, "lisi");System.out.println(s);}
}
package a04_反射獲取成員變量;public class Student {private String name;private int age;public String gender;public Student() {}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}
}

5.反射獲取成員方法

Class 類中用于獲取成員方法的方法Method[] getMethods ():返回所有公共成員方法對象的數組,包括繼承的Method[] getDeclaredMethods ():返回所有成員方法對象的數組,不包括繼承的Method getMethod (String name, Class < ?>...parameterTypes) :返回單個公共成員方法對象Method getDeclaredMethod (String name, Class < ?>...parameterTypes):返回單個成員方法對象
Method 類中用于創建對象的方法Object invoke (Object obj, Object...args):運行方法參數一:用 obj 對象調用該方法參數二:調用方法的傳遞的參數(如果沒有就不寫)返回值:方法的返回值(如果沒有就不寫)獲取方法的修飾符
獲取方法的名字
獲取方法的形參
獲取方法的返回值
獲取方法的拋出的異常
package a05_反射獲取成員方法;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;public class Test {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {//1. 獲取class字節碼文件對象Class clazz = Class.forName("a05_反射獲取成員方法.Student");//2. 獲取里面所有的方法對象(包含父類中所有的公共方法)/*Method[] methods = clazz.getMethods();for (Method method : methods) {System.out.println(method);}*/// 獲取里面所有的方法對象(不能獲取父類的,但是可以獲取本類中私有的方法)Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {System.out.println(method);}// 獲取指定的單一方法Method m = clazz.getDeclaredMethod("eat", String.class);// 獲取方法的修飾符int modifiers = m.getModifiers();System.out.println(modifiers);// 獲取方法的名字String name = m.getName();System.out.println(name);// 獲取方法的形參Parameter[] parameters = m.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter);}//獲取方法的拋出的異常Class[] exceptionTypes = m.getExceptionTypes();for (Class exceptionType : exceptionTypes) {System.out.println(exceptionType);}//        Method 類中用于創建對象的方法
//          Object invoke (Object obj, Object...args):運行方法
//          參數一:用 obj 對象調用該方法
//          參數二:調用方法的傳遞的參數(如果沒有就不寫)
//          返回值:方法的返回值(如果沒有就不寫)Student s = new Student();m.setAccessible(true);//參數一s:表示方法的調用者//參數二"漢堡包":表示在調用方法的時候傳遞的實際參String result = (String) m.invoke(s, "漢堡包");System.out.println(result);}
}
package a05_反射獲取成員方法;import java.io.IOException;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void sleep() {System.out.println("睡覺");}private String eat(String something) throws IOException, NullPointerException, ClassCastException {System.out.println("在吃" + something);return "奧里給";}private void eat(String something, int a) {System.out.println("在吃" + something);}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}

6.綜合練習

保存任意對象數據

package a06_綜合練習.a01_保存任意對象數據;import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;public class Test {public static void main(String[] args) throws IllegalAccessException, IOException {/*對于任意一個對象,都可以把對象所有的字段名和值,保存到文件中去*/Student s = new Student("小A", 23, '女', 167.5, "睡覺");Teacher t = new Teacher("播妞", 10000);saveObject(s);}//把對象里面所有的成員變量名和值保存到本地文件中public static void saveObject(Object obj) throws IllegalAccessException, IOException {//1.獲取字節碼文件的對象Class clazz = obj.getClass();//2. 創建IO流BufferedWriter bw = new BufferedWriter(new FileWriter("myreflect\\a.txt"));//3. 獲取所有的成員變量Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);//獲取成員變量的名字String name = field.getName();//獲取成員變量的值Object value = field.get(obj);//寫出數據bw.write(name + "=" + value);bw.newLine();}bw.close();}
}
package a06_綜合練習.a01_保存任意對象數據;public class Student {private String name;private int age;private char gender;private double height;private String hobby;public Student() {}public Student(String name, int age, char gender, double height, String hobby) {this.name = name;this.age = age;this.gender = gender;this.height = height;this.hobby = hobby;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}public String getHobby() {return hobby;}public void setHobby(String hobby) {this.hobby = hobby;}
}
package a06_綜合練習.a01_保存任意對象數據;public class Teacher {private String name;private double salary;public Teacher() {}public Teacher(String name, double salary) {this.name = name;this.salary = salary;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}
}

利用反射動態的創建對象和運行方法

package a06_綜合練習.a02_利用反射動態的創建對象和運行方法;import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;public class Test {public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException, IOException {/*反射可以跟配置文件結合的方式,動態的創建對象,并調用方法*///1.讀取配置文件中的信息Properties prop = new Properties();FileInputStream fis = new FileInputStream("a26_反射\\prop.properties");prop.load(fis);fis.close();System.out.println(prop);//2.獲取全類名和方法名String className = (String) prop.get("classname");String methodName = (String) prop.get("method");System.out.println(className);System.out.println(methodName);//3.利用反射創建對象并運行方法Class clazz = Class.forName(className);//獲取構造方法Constructor con = clazz.getDeclaredConstructor();Object o = con.newInstance();System.out.println(o);//獲取成員方法并運行Method method = clazz.getDeclaredMethod(methodName);method.setAccessible(true);method.invoke(o);}
}
package a06_綜合練習.a02_利用反射動態的創建對象和運行方法;public class Teacher {private String name;private double salary;public Teacher() {}public Teacher(String name, double salary) {this.name = name;this.salary = salary;}public void teach() {System.out.println("老師在教書!");}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}
}
package a06_綜合練習.a02_利用反射動態的創建對象和運行方法;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public void study(){System.out.println("學生在學習!");}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
classname=a06_綜合練習.a02_利用反射動態的創建對象和運行方法.Teacher
method=teach

反射總結:

1.反射的作用獲取任意一個類中的所有信息結合配置文件動態創建對象
2.獲得 class 字節碼文件對象的三種方式Class.forName ("全類名");類名.class對象.getClass ();
3.如何獲取構造方法、成員方法、成員變量get:獲取Constructor:構造方法Field:成員變量Method:方法set:設置Parameter:參數Modifiers:修飾符Declared:私有的
動態代理

思路分析

程序為什么需要代理?代理長什么樣?對象如果嫌身上干的事太多的話,可以通過代理來轉移部分職責對象有什么方法想被代理,代理就一定要有對應的方法
中介如何知道要派有唱歌、跳舞方法的代理呢?接口1.為什么需要代理?代理可以無侵入式的給對象增強其他的功能調用者——>代理——>對象
2.代理長什么樣?代理里面就是對象要被代理的方法
3.Java通過什么來保證代理的樣子?通過接口保證,后面的對象和代理需要實現同一個接口接口中就是被代理的所有方法

代碼實現

package a02_代碼實現;public class Test {public static void main(String[] args) {/*需求:外面的人想要大明星唱一首歌1. 獲取代理的對象代理對象 = ProxyUtil.createProxy(大明星的對象);2. 再調用代理的唱歌方法代理對象.唱歌的方法("只因你太美");*///1. 獲取代理的對象BigStar bigStar = new BigStar("雞哥");Star proxy = ProxyUtil.createProxy(bigStar);//2. 調用唱歌的方法String result = proxy.sing("只因你太美");System.out.println(result);//3. 調用跳舞的方法proxy.dance();}
}
package a02_代碼實現;public class BigStar implements Star {private String name;public BigStar() {}public BigStar(String name) {this.name = name;}//唱歌@Overridepublic String sing(String name) {System.out.println(this.name + "正在唱" + name);return "謝謝";}//跳舞@Overridepublic void dance() {System.out.println(this.name + "正在跳舞");}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
package a02_代碼實現;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil {
//    方法的作用:
//      給一個明星的對象,創建一個代理
//    形參:
//      被代理的明星對象
//    返回值:
//      給明星創建的代理//    需求:
//      外面的人想要大明星唱一首歌
//      1.獲取代理的對象
//          代理對象 = ProxyUtil.createProxy (大明星的對象);
//      2.再調用代理的唱歌方法
//          代理對象.唱歌的方法("只因你太美");public static Star createProxy(BigStar bigStar){/* java.lang.reflect.Proxy類: 提供了為對象產生代理對象的方法:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)參數一: 用于指定用哪個類加載器,去加載生成的代理類參數二: 指定接口,這些接口用于指定生成的代理長什么,也就是有哪些方法參數三: 用來指定生成的代理對象要干什么事情*/Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),//參數一: 用于指定用哪個類加載器,去加載生成的代理類new Class[]{Star.class},//參數二: 指定接口,這些接口用于指定生成的代理長什么,也就是有哪些方法//參數三: 用來指定生成的代理對象要干什么事情new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/** 參數一: 代理的對象* 參數二: 要運行的方法 sing* 參數三: 調用sing方法時,傳遞的實參* */if("sing".equals(method.getName())){System.out.println("準備話筒,收錢");}else if("dance".equals(method.getName())){System.out.println("準備場地,收錢");}//去找大明星開始唱歌或者跳舞//代碼的表現形式: 調用大明星里面唱歌或者跳舞的方法return method.invoke(bigStar,args);}});return star;}
}
package a02_代碼實現;public interface Star {//我們可以把所有想要被代理的方法定義在接口當中//唱歌public abstract String sing(String name);//跳舞public abstract void dance();
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/83282.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/83282.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/83282.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【仿muduo庫實現并發服務器】使用正則表達式提取HTTP元素

使用正則表達式提取HTTP元素 1.正則表達式2.正則庫的使用3.使用正則表達式提取HTTP請求行 1.正則表達式 正則表達式它其實是描述了一種字符串匹配的模式&#xff0c;它可以用來在一個字符串中檢測一個特定格式的字串&#xff0c;以及可以將符合特定規則的字串進行替換或者提取…

顯示即戰略:鐵電液晶如何成為 “數字中國” 的 “像素基石”?

一、顯示技術&#xff1a;數字時代的核心戰略支點 &#xff08;一&#xff09;從 “視覺窗口” 到 “戰略基礎設施” 在數字經濟蓬勃發展的當下&#xff0c;顯示技術早已超越了單純的 “視覺呈現” 范疇&#xff0c;成為連接人與數字世界的關鍵接口。從智能手機、平板電腦到車…

適合小白的超詳細配置YOLOv8教程(畢設必看)(訓練自己數據集)(Pycharm保姆級安裝教程)(lablme的使用)(GPU版)

目錄 1.Pycharm的安裝和虛擬環境調用&#xff08;已經安裝好的可以跳過此步驟&#xff09; 1.1 下載pycharm軟件 1.2 調用已創建虛擬環境&#xff08;調用上一篇教程中創建好的虛擬環境&#xff09; 2.標注自己數據集&#xff08;已有數據集的這部分可跳過&#xff09; 2.1…

EC800X QuecDuino開發板介紹

支持的模組列表 EG800KEC800MEC800GEC800E 功能列表 基本概述 EC800X QuecDuino EVB 搭載移遠 EC800 系列模組。支持模組型號為&#xff1a; EC800M 系列、EC800K 系列、EG800K 系列、EC800E 系列等。 渲染圖 開發板的主要組件、接口布局見下圖 資料下載 EC800X-QuecDui…

Unity + HybirdCLR熱更新 入門篇

官方文檔 HybridCLR | HybridCLRhttps://hybridclr.doc.code-philosophy.com/docs/intro 什么是HybirdCLR? HybridCLR&#xff08;原名 huatuo&#xff09;是一個專為 Unity 項目設計的C#熱更新解決方案&#xff0c;它通過擴展 IL2CPP 運行時&#xff0c;使其支持動態加載和…

類 Excel 數據填報

類 Excel 填報模式&#xff0c;滿足用戶 Excel 使用習慣 數據填報&#xff0c;可作為獨立的功能模塊&#xff0c;用于管理業務流程、匯總采集數據&#xff0c;以及開發各類數據報送系統&#xff0c;因此&#xff0c;對于報表工具而言&#xff0c;其典型場景之一就是利用報表模…

MySQL 8.0 OCP 英文題庫解析(十)

Oracle 為慶祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免費考取原價245美元的MySQL OCP 認證。 從今天開始&#xff0c;將英文題庫免費公布出來&#xff0c;并進行解析&#xff0c;幫助大家在一個月之內輕松通過OCP認證。 本期公布試題81~90 試題81:…

JavaScript 性能優化實戰:從原理到框架的全棧優化指南

在 Web 應用復雜度指數級增長的今天&#xff0c;JavaScript 性能優化已成為衡量前端工程質量的核心指標。本文將結合現代瀏覽器引擎特性與一線大廠實踐經驗&#xff0c;構建從基礎原理到框架定制的完整優化體系&#xff0c;助你打造高性能 Web 應用。 一、性能優化基礎&#x…

基于Web的分布式圖集管理系統架構設計與實踐

引言&#xff1a;為什么需要分布式圖集管理&#xff1f; 在現代Web圖形應用中&#xff0c;紋理圖集&#xff08;Texture Atlas&#xff09;技術是優化渲染性能的關鍵手段。傳統的圖集制作流程通常需要美術人員使用專業工具&#xff08;如TexturePacker&#xff09;離線制作&am…

鴻蒙OS在UniApp中集成Three.js:打造跨平臺3D可視化應用#三方框架 #Uniapp

在UniApp中集成Three.js&#xff1a;打造跨平臺3D可視化應用 引言 在最近的一個項目中&#xff0c;我們需要在UniApp應用中展示3D模型&#xff0c;并實現實時交互功能。經過技術選型和實踐&#xff0c;我們選擇了Three.js作為3D渲染引擎。本文將分享我們在UniApp中集成Three.…

Flask中關于app.url_map屬性的用法

目錄 一、app.url_map 是什么? 二、可以查看哪些信息? 三、示例:打印所有路由 四、結合 url_for() 使用 五、常見用途場景 六、結合 Flask CLI 使用 總結 app.url_map 是 Flask 中非常重要的一個屬性,用于查看或操作整個應用的 URL 路由映射表(routing map)。它展…

SpringBoot項目搭建指南

SpringBoot項目搭建指南 文章目錄 SpringBoot項目搭建指南一、SpringBoot項目搭建1.1 SpringBoot 版本選擇1.2 SpringBoot 框架引入方式1.2.1 繼承 Starter Parent POM1.2.2 不使用 Parent POM 來使用 Spring Boot 1.3 SpringBoot 打包插件 二、日志框架引入2.1 引入SpringBoot…

數據庫系統概論(十六)數據庫安全性(安全標準,控制,視圖機制,審計與數據加密)

數據庫系統概論&#xff08;十六&#xff09;數據庫安全性 前言一、數據庫安全性1. 什么是數據庫安全性&#xff1f;2. 為何會存在安全問題&#xff1f; 二、安全標準的發展1. 早期的“開拓者”&#xff1a;TCSEC標準2. 走向國際統一&#xff1a;CC標準3. TCSEC和CC標準有什么不…

Jvm 元空間大小分配原則

JVM元空間&#xff08;Metaspace&#xff09;的大小分配原則與系統物理內存密切相關&#xff0c;但并不是直接等比例分配&#xff0c;而是通過一系列參數和JVM的動態管理機制來確定。下面從原理和實際行為兩方面詳細說明&#xff1a; 1. 元空間&#xff08;Metaspace&#xff0…

編程之巔:語言的較量

第一章&#xff1a;代碼之城的召集令 在遙遠的數字大陸上&#xff0c;有一座名為“代碼之城”的神秘都市。這里居住著各種編程語言的化身&#xff0c;他們以擬人化的形態生活&#xff0c;每種語言都有獨特的性格與技能。Python是個優雅的學者&#xff0c;C是個硬核戰士&#x…

飛牛fnNAS裝機之迷你小主機的利舊

前幾天找Console線的時候,翻出一臺迷你小主機,想起來以前是做“軟路由”用的,現在用不上了。本想放回箱子,但突然想起最近正在做飛牛NAS的專題,不如將其改造成NAS得了。 這個東東有HDMI、VGA接口,2個USB(其中一個支持3.0),還有4個網口。 打開機蓋,看看內部情況。發現…

uv:一個現代化的 Python 依賴管理工具

在 Python 的生態系統中&#xff0c;依賴管理和 Python 版本管理一直是開發者關注的核心問題。傳統的工具如 pip、poetry 和 pyenv 雖然功能強大&#xff0c;但在性能和使用體驗上仍有改進空間。uv 是由 Python 核心開發者開發的 現代化依賴管理工具&#xff0c;旨在提供更快、…

ubuntu 22.04安裝k8s高可用集群

文章目錄 1.環境準備&#xff08;所有節點&#xff09;1.1 關閉無用服務1.2 環境和網絡1.3 apt源1.4 系統優化1.5 安裝nfs客戶端 2. 裝containerd&#xff08;所有節點&#xff09;3. master的高可用方案&#xff08;master上操作&#xff09;3.1 安裝以及配置haproxy&#xff…

PnP(Perspective-n-Point)算法 | 用于求解已知n個3D點及其對應2D投影點的相機位姿

什么是PnP算法&#xff1f; PnP 全稱是 Perspective-n-Point&#xff0c;中文叫“n點透視問題”。它的目標是&#xff1a; 已知一些空間中已知3D點的位置&#xff08;世界坐標&#xff09;和它們對應的2D圖像像素坐標&#xff0c;求解攝像機的姿態&#xff08;位置和平移&…

QT-JSON

#include <QJsonDocument>#include <QJsonObject>#include <QJsonArray>#include <QFile>#include <QDebug>void createJsonFile() {// 創建一個JSON對象 鍵值對QJsonObject jsonObj;jsonObj["name"] "John Doe";jsonObj[…