新手初學(xué)Java網(wǎng)絡(luò)編程
運行線程
創(chuàng)建Thread的子類
public class ThreadChild extends Thread { @Override public void run() { while (true) { System.out.println("run"); } } }
public class Test { public static void main(String[] args) throws Exception { ThreadChild t = new ThreadChild(); t.start(); } }
創(chuàng)建Thread傳入Runnable接口實現(xiàn)類
public class RunnableImpl implements Runnable { @Override public void run() { while (true) { System.out.println("run"); } } }
public class Test { public static void main(String[] args) throws Exception { Thread t = new Thread(new RunnableImpl()); t.start(); } }
回調(diào)
ExecutorService線程池的Submit()可接收Runnable或者Callable.Callable執(zhí)行結(jié)束后有返回值,Runnable執(zhí)行結(jié)束后沒有返回值.可以通過submit的返回對象Future的get方法獲取返回返回值,需要注意的是get方法是一個阻塞方法.若線程沒有執(zhí)行完畢,則會阻塞get()直到線程執(zhí)行結(jié)束后返回數(shù)據(jù).
public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newFixedThreadPool(10); Future<Integer> future = executorService.submit(() -> { TimeUnit.SECONDS.sleep( 3); return 1; }); Future<?> future2 = executorService.submit(() -> { }); Future<String> future3 = executorService.submit(() -> { }, "aaa"); System.out.println(future.get()); System.out.println(future2.get()); System.out.println(future3.get()); }
同步方法
synchronized關(guān)鍵字和方法組合使用后,該方法是一個同步方法。同步方法都有一個隱試的鎖,多個線程同時執(zhí)行該方法時,只能順序執(zhí)行,未強到鎖的線程處于阻塞狀態(tài)。另外靜態(tài)方法和非靜態(tài)方法使用的是不同的鎖,非靜態(tài)方法的鎖是對象鎖,若兩個線程通過兩個該類的對象調(diào)用那么互不影響。靜態(tài)方法是類鎖,即本類的Class對象。同步方法無法指定鎖資源,要么是this鎖,要么是Class鎖。
public class Test { public static void main(String[] args) throws Exception { Test test = new Test(); Thread t1 = new Thread(()->{ test.synFunction(); }); Thread t2 = new Thread(()->{ test.synFunction(); }); t1.start(); t2.start(); } public synchronized void synFunction(){ try { System.out.println("-------------"); TimeUnit.SECONDS.sleep(3); }catch (Exception e) {} } }
public class Test { public static void main(String[] args) throws Exception { Thread t1 = new Thread(()->{ Test.synFunction(); }); Thread t2 = new Thread(()->{ Test.synFunction(); }); t1.start(); t2.start(); } public static synchronized void synFunction(){ try { System.out.println("-------------"); TimeUnit.SECONDS.sleep(3); }catch (Exception e) {} } }
同步塊
同步代碼塊可以指定鎖對象,非靜態(tài)方法可以指定任意的對象鎖,或者任意的類鎖。但靜態(tài)方法只能使用任意的類鎖。
public class Test { public static void main(String[] args) throws Exception { Test lock = new Test(); Thread t1 = new Thread(() -> { lock.synFunction(); }); Thread t2 = new Thread(() -> { lock.synFunction(); }); t1.start(); t2.start(); } public void synFunction() { synchronized (this) {//對象鎖 try { System.out.println("-------------"); TimeUnit.SECONDS.sleep(3); } catch (Exception e) { } } } }
public class Test { public static void main(String[] args) throws Exception { Test lock1 = new Test(); Test lock2 = new Test(); Thread t1 = new Thread(() -> { lock1.synFunction(lock1); }); Thread t2 = new Thread(() -> { lock2.synFunction(lock2); }); t1.start(); t2.start(); } public void synFunction(Object lock) { synchronized (lock) {//對象鎖 try { System.out.println("-------------"); TimeUnit.SECONDS.sleep(3); } catch (Exception e) { } } } }
public class Test { public static void main(String[] args) throws Exception { Test lock1 = new Test(); Test lock2 = new Test(); Thread t1 = new Thread(() -> { lock1.synFunction(); }); Thread t2 = new Thread(() -> { lock2.synFunction(); }); t1.start(); t2.start(); } public void synFunction() { synchronized (Test.class) {//類鎖 try { System.out.println("-------------"); TimeUnit.SECONDS.sleep(3); } catch (Exception e) { } } } }
public class Test { public static void main(String[] args) throws Exception { Thread t1 = new Thread(() -> { Test.synFunction(); }); Thread t2 = new Thread(() -> { Test.synFunction(); }); t1.start(); t2.start(); } public static void synFunction() { synchronized (Object.class) {//類鎖 try { System.out.println("-------------"); TimeUnit.SECONDS.sleep(3); } catch (Exception e) { } } } }
死鎖
當(dāng)多個線程競爭鎖時,可能會導(dǎo)致死鎖。一個線程由于沒有得到一個鎖而阻塞它也不會釋放已經(jīng)獲取的鎖。方法1獲取鎖的順序是Test.class,Object.class。方法2獲取鎖的順序是Object.class,Test.class。程序會陷入死鎖。
public class Test { public static void main(String[] args) throws Exception { Thread t1 = new Thread(() -> { Test.synFunction1(); }); Thread t2 = new Thread(() -> { Test.synFunction2(); }); t1.start(); t2.start(); } public static void synFunction1() { synchronized (Test.class) {// 類鎖 try { System.out.println("synFunction1-------------AAAAAAAAAAAAA"); synchronized (Object.class) {// 類鎖 try { System.out.println("synFunction1-------------bbbbbbbbbbbbb"); } catch (Exception e) { } } } catch (Exception e) { } } } public static void synFunction2() { synchronized (Object.class) {// 類鎖 try { System.out.println("synFunction2-------------AAAAAAAAAAAAA"); } catch (Exception e) { } synchronized (Test.class) {// 類鎖 try { System.out.println("synFunction2-------------bbbbbbbbbbbbb"); } catch (Exception e) { } } } } }
優(yōu)先級
不是所有線程創(chuàng)建時都是均等的,每個線程都有一個優(yōu)先級,指定從0-10的整數(shù)。當(dāng)多個線程運行時,虛擬機通常只運行最高優(yōu)先級的線程,但這并不是一個嚴格的規(guī)則。在Java中10是最高優(yōu)先級,0是最低優(yōu)先級。默認優(yōu)先級為5.并不是所有操作系統(tǒng)都支持這11個優(yōu)先級。例如Windows只有7個優(yōu)先級。優(yōu)先級(1,2)(3,4)(6,7)(8,9)會做同樣的處理。
public class Test { public static void main(String[] args) throws Exception { Thread t1 = new Thread(() -> { Test.synFunction("aaaaaaaaaaa"); }); Thread t2 = new Thread(() -> { Test.synFunction("bbbbbbbbbb"); }); t2.setPriority(9); t1.setPriority(1); t1.start(); t2.start(); } public static void synFunction(String name) { System.out.println(name+"--------------"); } }
暫停
為了能讓其他線程有機會運行,一個線程有8中方式可以暫?;蛘咧甘舅鼫蕚鋾和?。
可以對IO阻塞
要讓網(wǎng)絡(luò)程序中的線程自動放棄CPU控制權(quán),最常見的方式是IO阻塞。由于CPU比網(wǎng)絡(luò)和磁盤快的多,網(wǎng)絡(luò)程序經(jīng)常會在等待數(shù)據(jù)從網(wǎng)絡(luò)到達或向網(wǎng)絡(luò)發(fā)送數(shù)據(jù)時阻塞。即使只阻塞幾毫秒,這一點時間也足夠其他線程用來完成重要的任務(wù)。
可以對同步對象阻塞
線程在進入一個同步方法或代碼塊時也會阻塞。如果這個線程沒有所同步對象的鎖,而其他線程擁有這個鎖,這個線程就會暫停,直到鎖被釋放為止。如果這個鎖永遠不會釋放,那么這個線程會永久停止。
可以放棄
調(diào)用Thread.yield()靜態(tài)方法可以做到顯試的放棄線程控制權(quán),這將通知虛擬機,可以優(yōu)先執(zhí)行其他線程。放棄并不會釋放這個線程擁有的鎖,因此在理想情況下被放棄的線程不要做任何的同步。如果等待運行的其他線程都是因為這個線程所擁有的同步資源而阻塞,那么這些線程將不能運行。實際上,控制權(quán)將回到唯一可以運行的線程,即剛剛放棄的這個線程,這很大程度上失去了放棄的意義。
public class Test { public static void main(String[] args) throws Exception { Thread t1 = new Thread(() -> { Test.synFunction("aaaaaaaaaaa"); }); Thread t2 = new Thread(() -> { Test.synFunction2("bbbbbbbbbb"); }); t1.start(); t2.start(); } public static void synFunction(String name) { for (int i = 0;; i++) { Thread.yield(); System.out.println(name + "--------------" + i); } } public static void synFunction2(String name) { for (int i = 0;; i++) System.out.println(name + "--------------"+i); } }
可以休眠
休眠是更有利的放棄方式。放棄只是表示線程愿意暫停,讓其他有相同優(yōu)先級的線程有機會運行,而進入休眠的線程有所不同,不管有沒有其他線程準備運行,休眠線程都會暫停。這樣一來,不只是其他有相同優(yōu)先級的線程會得到機會,還會給較低優(yōu)先級的線程運行機會。不過進入休眠的線程仍然擁有它已經(jīng)獲得得所有鎖。因此其他需要相同鎖得線程依然會阻塞,要避免在同步方法或塊內(nèi)讓線程休眠。
public class Test { public static void main(String[] args) throws Exception { Thread t1 = new Thread(() -> { Test.synFunction("aaaaaaaaaaa"); }); Thread t2 = new Thread(() -> { Test.synFunction2("bbbbbbbbbb"); }); t1.start(); t2.start(); } public synchronized static void synFunction(String name) { try { System.out.println(name); Thread.sleep(1000 * 10); } catch (Exception e) { } } public synchronized static void synFunction2(String name) { System.out.println(name); } }
package com.datang.bingxiang.demo; import java.util.concurrent.TimeUnit; public class Test { public static void main(String[] args) throws Exception { Thread t1 = new Thread(() -> { Test.synFunction("aaaaaaaaaaa"); }); Thread t2 = new Thread(() -> { Test.synFunction2("bbbbbbbbbb"); }); t1.start(); t2.start(); } public synchronized static void synFunction(String name) { try { System.out.println(name); Thread.sleep(1000 * 3, 999999);//3000毫秒+999999毫秒(第二個參數(shù)不能超過999999,也就是不能超過1毫秒) } catch (Exception e) { System.out.println(e); } } public synchronized static void synFunction2(String name) { System.out.println(name); } }
可以連接另一個線程
連接線程(既調(diào)用join()方法得線程A)等待被連接的線程(join()方法所屬的線程對象B)執(zhí)行完畢后才會執(zhí)行。在A線程調(diào)用B線程的join()A線程會等待B線程執(zhí)行結(jié)束后才會繼續(xù)執(zhí)行。要注意的是A線程并不會釋放已經(jīng)獲取的鎖資源。
public class Test { public static void main(String[] args) throws Exception { Thread t2 = new Thread(() -> { Test.synFunction2("bbbbbbbbbb"); }); Thread t1 = new Thread(() -> { Test.synFunction("aaaaaaaaaaa",t2); }); t1.start(); t2.start(); } public static void synFunction(String name,Thread t) { try { t.join(); //t.join(1000); //t.join(1000,999999); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 5; i++) { System.out.println(name); } } public static void synFunction2(String name) { try { Thread.sleep(1000*3); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 5; i++) { System.out.println(name); } } }
可以等待一個對象
線程可以等待一個它鎖定的對象.在等待時,它會釋放這個對象的鎖并暫停,直到它得到其他線程的通知.另一個線程以某種方式修改這個對象,通知等待對象的線程,然后繼續(xù)執(zhí)行.等待會暫停執(zhí)行,直到一個對象或資源到達某種狀態(tài).實際上,要等待某個特定的對象,希望暫停的線程首先必須使用synchronized獲得這個對象的鎖,然后調(diào)用這個對象的三個重載wait()方法之一.
public class Demo { public static void main(String[] args) throws Exception { Demo d = new Demo(); Thread t1 = new Thread(() -> { d.a(); }); Thread t2 = new Thread(() -> { d.b(); }); t1.start(); t2.start(); } boolean flag = true; public synchronized void a() { try { while (true) { if (flag) { System.out.println("執(zhí)行AAAAAAAAAAA"); flag = false; } else { wait();//等待,不限制等待時間 //wait(1000);//等待指定的時間,沒有被notify喚醒也可以自己退出等待 //wait(1000,999999);//毫秒+納秒的等待時間 } notify(); } } catch (Exception e) { } } public synchronized void b() { try { while (true) { if (!flag) { System.out.println("執(zhí)行BBBBBBBBBBB"); flag = true; } else { wait(); } notify(); } } catch (Exception e) { } } }
可以結(jié)束
線程要以合理的方式放棄CPU控制權(quán),一種方式是結(jié)束.當(dāng)run()方法返回線程時,線程將撤銷,其他線程可以接管CPU.在網(wǎng)絡(luò)應(yīng)用程序中,包裝一個阻塞操作的線程往往會這么做,例如線程從服務(wù)器下載一個文件,這樣應(yīng)用程序的其他部分就不會被阻塞.另一方面,如果run()方法太簡單,總是很快結(jié)束,而不會紫色,那就存在一個很實際的問題:到底有沒有必要生成一個線程.虛擬機在建立和撤銷線程時會有很大的開銷.如果線程會在極端的時間內(nèi)結(jié)束,那么使用一次簡單的方法調(diào)用而不是單獨的線程可能會結(jié)束的更快.
可以被更高優(yōu)先級線程搶占
Thread的setPriority(int priority)
設(shè)置線程的優(yōu)先級.
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
IDEA下使用Spring Boot熱加載的實現(xiàn)
本文主要介紹了IDEA下使用Spring Boot熱加載的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06SpringMVC高級開發(fā)功能實現(xiàn)過程解析
這篇文章主要介紹了SpringMVC高級開發(fā)功能實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例
這篇文章主要介紹了Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例,用于構(gòu)建靜態(tài)對象以及實現(xiàn)線程同步等,需要的朋友可以參考下2015-09-09Map按單個或多個Value排序當(dāng)Value相同時按Key排序
Map可以先按照value進行排序,然后按照key進行排序。 或者先按照key進行排序,然后按照value進行排序,這樣操作都行,這篇文章主要介紹了Map按單個或多個Value排序,當(dāng)Value相同時按Key排序,需要的朋友可以參考下2023-02-02SpringBoot結(jié)合mybatis-plus實現(xiàn)分頁的項目實踐
本文主要介紹了SpringBoot結(jié)合mybatis-plus實現(xiàn)分頁的項目實踐,主要基于MyBatis-Plus 自帶的分頁插件 PaginationInterceptor,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06