新手初學(xué)Java網(wǎng)絡(luò)編程
運(yùn)行線程
創(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接口實(shí)現(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é)束后沒(méi)有返回值.可以通過(guò)submit的返回對(duì)象Future的get方法獲取返回返回值,需要注意的是get方法是一個(gè)阻塞方法.若線程沒(méi)有執(zhí)行完畢,則會(huì)阻塞get()直到線程執(zhí)行結(jié)束后返回?cái)?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)鍵字和方法組合使用后,該方法是一個(gè)同步方法。同步方法都有一個(gè)隱試的鎖,多個(gè)線程同時(shí)執(zhí)行該方法時(shí),只能順序執(zhí)行,未強(qiáng)到鎖的線程處于阻塞狀態(tài)。另外靜態(tài)方法和非靜態(tài)方法使用的是不同的鎖,非靜態(tài)方法的鎖是對(duì)象鎖,若兩個(gè)線程通過(guò)兩個(gè)該類的對(duì)象調(diào)用那么互不影響。靜態(tài)方法是類鎖,即本類的Class對(duì)象。同步方法無(wú)法指定鎖資源,要么是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) {} } }
同步塊
同步代碼塊可以指定鎖對(duì)象,非靜態(tài)方法可以指定任意的對(duì)象鎖,或者任意的類鎖。但靜態(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) {//對(duì)象鎖 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) {//對(duì)象鎖 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)多個(gè)線程競(jìng)爭(zhēng)鎖時(shí),可能會(huì)導(dǎo)致死鎖。一個(gè)線程由于沒(méi)有得到一個(gè)鎖而阻塞它也不會(huì)釋放已經(jīng)獲取的鎖。方法1獲取鎖的順序是Test.class,Object.class。方法2獲取鎖的順序是Object.class,Test.class。程序會(huì)陷入死鎖。
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)先級(jí)
不是所有線程創(chuàng)建時(shí)都是均等的,每個(gè)線程都有一個(gè)優(yōu)先級(jí),指定從0-10的整數(shù)。當(dāng)多個(gè)線程運(yùn)行時(shí),虛擬機(jī)通常只運(yùn)行最高優(yōu)先級(jí)的線程,但這并不是一個(gè)嚴(yán)格的規(guī)則。在Java中10是最高優(yōu)先級(jí),0是最低優(yōu)先級(jí)。默認(rèn)優(yōu)先級(jí)為5.并不是所有操作系統(tǒng)都支持這11個(gè)優(yōu)先級(jí)。例如Windows只有7個(gè)優(yōu)先級(jí)。優(yōu)先級(jí)(1,2)(3,4)(6,7)(8,9)會(huì)做同樣的處理。
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+"--------------"); } }
暫停
為了能讓其他線程有機(jī)會(huì)運(yùn)行,一個(gè)線程有8中方式可以暫停或者指示它準(zhǔn)備暫停。
可以對(duì)IO阻塞
要讓網(wǎng)絡(luò)程序中的線程自動(dòng)放棄CPU控制權(quán),最常見的方式是IO阻塞。由于CPU比網(wǎng)絡(luò)和磁盤快的多,網(wǎng)絡(luò)程序經(jīng)常會(huì)在等待數(shù)據(jù)從網(wǎng)絡(luò)到達(dá)或向網(wǎng)絡(luò)發(fā)送數(shù)據(jù)時(shí)阻塞。即使只阻塞幾毫秒,這一點(diǎn)時(shí)間也足夠其他線程用來(lái)完成重要的任務(wù)。
可以對(duì)同步對(duì)象阻塞
線程在進(jìn)入一個(gè)同步方法或代碼塊時(shí)也會(huì)阻塞。如果這個(gè)線程沒(méi)有所同步對(duì)象的鎖,而其他線程擁有這個(gè)鎖,這個(gè)線程就會(huì)暫停,直到鎖被釋放為止。如果這個(gè)鎖永遠(yuǎn)不會(huì)釋放,那么這個(gè)線程會(huì)永久停止。
可以放棄
調(diào)用Thread.yield()靜態(tài)方法可以做到顯試的放棄線程控制權(quán),這將通知虛擬機(jī),可以優(yōu)先執(zhí)行其他線程。放棄并不會(huì)釋放這個(gè)線程擁有的鎖,因此在理想情況下被放棄的線程不要做任何的同步。如果等待運(yùn)行的其他線程都是因?yàn)檫@個(gè)線程所擁有的同步資源而阻塞,那么這些線程將不能運(yùn)行。實(shí)際上,控制權(quán)將回到唯一可以運(yùn)行的線程,即剛剛放棄的這個(gè)線程,這很大程度上失去了放棄的意義。
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)先級(jí)的線程有機(jī)會(huì)運(yùn)行,而進(jìn)入休眠的線程有所不同,不管有沒(méi)有其他線程準(zhǔn)備運(yùn)行,休眠線程都會(huì)暫停。這樣一來(lái),不只是其他有相同優(yōu)先級(jí)的線程會(huì)得到機(jī)會(huì),還會(huì)給較低優(yōu)先級(jí)的線程運(yùn)行機(jī)會(huì)。不過(guò)進(jìn)入休眠的線程仍然擁有它已經(jīng)獲得得所有鎖。因此其他需要相同鎖得線程依然會(huì)阻塞,要避免在同步方法或塊內(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毫秒(第二個(gè)參數(shù)不能超過(guò)999999,也就是不能超過(guò)1毫秒) } catch (Exception e) { System.out.println(e); } } public synchronized static void synFunction2(String name) { System.out.println(name); } }
可以連接另一個(gè)線程
連接線程(既調(diào)用join()方法得線程A)等待被連接的線程(join()方法所屬的線程對(duì)象B)執(zhí)行完畢后才會(huì)執(zhí)行。在A線程調(diào)用B線程的join()A線程會(huì)等待B線程執(zhí)行結(jié)束后才會(huì)繼續(xù)執(zhí)行。要注意的是A線程并不會(huì)釋放已經(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); } } }
可以等待一個(gè)對(duì)象
線程可以等待一個(gè)它鎖定的對(duì)象.在等待時(shí),它會(huì)釋放這個(gè)對(duì)象的鎖并暫停,直到它得到其他線程的通知.另一個(gè)線程以某種方式修改這個(gè)對(duì)象,通知等待對(duì)象的線程,然后繼續(xù)執(zhí)行.等待會(huì)暫停執(zhí)行,直到一個(gè)對(duì)象或資源到達(dá)某種狀態(tài).實(shí)際上,要等待某個(gè)特定的對(duì)象,希望暫停的線程首先必須使用synchronized獲得這個(gè)對(duì)象的鎖,然后調(diào)用這個(gè)對(duì)象的三個(gè)重載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();//等待,不限制等待時(shí)間 //wait(1000);//等待指定的時(shí)間,沒(méi)有被notify喚醒也可以自己退出等待 //wait(1000,999999);//毫秒+納秒的等待時(shí)間 } 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()方法返回線程時(shí),線程將撤銷,其他線程可以接管CPU.在網(wǎng)絡(luò)應(yīng)用程序中,包裝一個(gè)阻塞操作的線程往往會(huì)這么做,例如線程從服務(wù)器下載一個(gè)文件,這樣應(yīng)用程序的其他部分就不會(huì)被阻塞.另一方面,如果run()方法太簡(jiǎn)單,總是很快結(jié)束,而不會(huì)紫色,那就存在一個(gè)很實(shí)際的問(wèn)題:到底有沒(méi)有必要生成一個(gè)線程.虛擬機(jī)在建立和撤銷線程時(shí)會(huì)有很大的開銷.如果線程會(huì)在極端的時(shí)間內(nèi)結(jié)束,那么使用一次簡(jiǎn)單的方法調(diào)用而不是單獨(dú)的線程可能會(huì)結(jié)束的更快.
可以被更高優(yōu)先級(jí)線程搶占
Thread的setPriority(int priority)
設(shè)置線程的優(yōu)先級(jí).
總結(jié)
本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
手把手教你從零設(shè)計(jì)一個(gè)java日志框架
Java里的各種日志框架,相信大家都不陌生。Log4j/Log4j2/Logback/jboss logging等等,其實(shí)這些日志框架核心結(jié)構(gòu)沒(méi)什么區(qū)別,只是細(xì)節(jié)實(shí)現(xiàn)上和其性能上有所不同。本文帶你從零開始,一步一步的設(shè)計(jì)一個(gè)日志框架2021-02-02IDEA下使用Spring Boot熱加載的實(shí)現(xiàn)
本文主要介紹了IDEA下使用Spring Boot熱加載的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06SpringMVC高級(jí)開發(fā)功能實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了SpringMVC高級(jí)開發(fā)功能實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例
這篇文章主要介紹了Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例,用于構(gòu)建靜態(tài)對(duì)象以及實(shí)現(xiàn)線程同步等,需要的朋友可以參考下2015-09-09Java實(shí)現(xiàn)英文句子中的單詞順序逆序輸出的方法
這篇文章主要介紹了Java實(shí)現(xiàn)英文句子中的單詞順序逆序輸出的方法,涉及java字符串遍歷、判斷、截取、輸出等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01Map按單個(gè)或多個(gè)Value排序當(dāng)Value相同時(shí)按Key排序
Map可以先按照value進(jìn)行排序,然后按照key進(jìn)行排序。 或者先按照key進(jìn)行排序,然后按照value進(jìn)行排序,這樣操作都行,這篇文章主要介紹了Map按單個(gè)或多個(gè)Value排序,當(dāng)Value相同時(shí)按Key排序,需要的朋友可以參考下2023-02-02SpringBoot結(jié)合mybatis-plus實(shí)現(xiàn)分頁(yè)的項(xiàng)目實(shí)踐
本文主要介紹了SpringBoot結(jié)合mybatis-plus實(shí)現(xiàn)分頁(yè)的項(xiàng)目實(shí)踐,主要基于MyBatis-Plus 自帶的分頁(yè)插件 PaginationInterceptor,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06