闭关修炼(一)多线程
2021年,記得元旦快了樂~~
文章目錄
- 線程與進程的區別
- 多線程應用場景
- 繼承方式創建多線程
- 同步和異步的概念?
- 同步
- 異步
- runnable接口創建多線程
- 使用匿名內部類方式創建多線程
- Callable方式創建多線程
- 線程池方式創建多線程
- 多線程常見API
- getId()
- getName()
- sleep()
- Thread.currentThread()
- stop()
- Thread()
- 守護線程與非守護線程
- 設置守護線程
- 多線程運行狀態
- join()方法作用
- 面試題順序執行T1,T2,T3
- 案例多線程分批處理數據
線程與進程的區別
-
什么是應用程序?
可以執行的軟件,在一個應用程序中,都會有一個進程。 -
在進程中,程序代碼如何執行?
在進程中,一定有一個主線程,java中的main -
什么是線程?
進程中的一條執行順序/流程/路徑。 -
什么是進程?
進程中有多個不同的執行路徑,進程是線程的集合,是正在執行中的程序,任務管理器中可以看見進程。 -
使用多線程的好處?
提高程序效率。
線程之間互不影響,因為線程都在自己獨立運行。
一個進程可中有多個線程,提高程序效率,提高用戶體驗。 -
注意事項
多線程并不提高單路徑執行速度,而是多路徑同時進行提高程序效率。
多線程應用場景
繼承方式創建多線程
創建線程有5種方式
繼承Thread接口,重寫(override)run方法,run方法就是線程需要執行的代碼。
class MyThread extends Thread{@Overridepublic void run() {for (int i =0 ; i< 30; i++){System.out.println(i);}} }啟動線程,實例化類,調用start方法,如果調用run方法還是單獨的執行run方法。
public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();for (int i =31 ; i< 60; i++){System.out.println("main" + i);}}啟動多線程,代碼不會從上往下執行。
同步和異步的概念?
同步
main函數中有方法①和方法②,每個方法都需要花費10秒時間,則需要20秒完成main函數。
代碼從上往下執行,被稱為同步。
同步中,main函數的方法之間存在依賴關系,存在執行順序,方法②等待方法①執行完畢后才能執行。
也叫做單線程。
異步
可以理解為多線程,方法①和方法②同時執行,每個方法都需要花費10秒時間,則需要10秒完成main函數。提高程序效率,線程間獨立,互不影響。
CPU調度時 異步中有執行權的概念,但在宏觀上看是同時進行的。
runnable接口創建多線程
創建類,實現runnable接口,重寫run方法
class MyThread2 implements Runnable{public void run() {for (int i =0 ; i< 30; i++){System.out.println("run" + i);}} }啟動線程方式,接口作為參數傳遞給Thread類,調用start方法
public static void main(String[] args) {MyThread2 myThread2 = new MyThread2();Thread thread = new Thread(myThread2);thread.start();}使用繼承方式創建線程還是使用runnable接口創建線程好?
使用接口方式,開發面向接口編程,繼承后不能再繼承,接口可以。
使用匿名內部類方式創建多線程
什么是匿名內部類?
沒有名稱的內部類。
例子:
abstract class Person{abstract void add(); } public static void main(String[] args) {Person person = new Person() {void add() {System.out.println("hello");}};person.add();}線程中也是類似,實例化Thread類,runnable接口使用匿名內部類進行實現
public static void main(String[] args) {Thread thread = new Thread(new Runnable() {public void run() {System.out.println("Hello~");}});thread.start();}Callable方式創建多線程
待更
線程池方式創建多線程
待更
多線程常見API
getId()
獲取線程的id,id唯一
class MyThread extends Thread{@Overridepublic void run() {for (int i =0 ; i< 30; i++){System.out.println(getId()+ "run" + i);}} }主線程id如何獲取?
System.out.println(Thread.currentThread().getId());主線程id為1
任何一個程序都會有一個主線程,本質也是一個線程。
getName()
獲取線程名稱
System.out.println(Thread.currentThread().getName());主線程的name是main
子線程名稱默認是Thread-0,Thread-1,Thread-2…
sleep()
暫停
class MyThread extends Thread{@Overridepublic void run() {for (int i =0 ; i< 30; i++){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getId()+ "run" + i);}} }Thread.currentThread()
獲取當前線程,在用Runnable接口的時候需要用這種方式獲取當前線程。
stop()
不安全,已過時
class MyThread extends Thread{@Overridepublic void run() {for (int i =0 ; i< 30; i++){if (i==5){stop();}System.out.println(getId()+ "run" + i);}} }Thread()
new Thread(new Runnable() {public void run() {System.out.println(1);}}, "線程名");守護線程與非守護線程
什么是守護線程?
和main函數相關。
守護線程和主線程一起銷毀。
如gc線程,垃圾回收機制中的單獨的一個線程,專門用來回收垃圾,主線程結束,守護線程一起結束。
什么是非守護線程?
與main函數互不影響。
自己創建線程叫做用戶線程,如果主線程停止了,不會影響用戶線程,用戶線程也叫非守護線程。
非守護線程演示代碼:
public static void main(String[] args) {new Thread(new Runnable() {@lombok.SneakyThrowspublic void run() {for (int i = 0; i <= 30; i++) {Thread.sleep(300);System.out.println(i);}}}, "線程名").start();System.out.println("主線程執行完畢");}執行結果:
主線程結束和非守護線程沒有依賴關系。
設置守護線程
thread.setDaemon(true);
讓守護線程和主線程一起銷毀。
public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@SneakyThrowspublic void run() {for (int i = 1000; i <= 3000; i++) {System.out.println(i);}}}, "線程名");thread.setDaemon(true);thread.start();for (int i = 0; i <500; i++){System.out.println(i);}System.out.println("主線程執行完畢");}多線程運行狀態
新建狀態
new Thread
就緒狀態
就緒狀態,等待cpu調度
運行狀態
獲取cpu調度權
死亡狀態
run方法執行完畢,或者stop方法
休眠(阻塞)狀態
調用了sleep方法或者wait()方法,運行狀態轉到阻塞狀態,再到就緒狀態
join()方法作用
現有線程A和線程B,線程A調用了線程B的join方法,A等待B線程執行完畢之后再繼續執行。也就是說線程A在調用B的join方法后,釋放了執行權,讓B先執行。
主線程讓子線程先執行,方法:在主函數中調用子線程的join方法,例子如下:
@SneakyThrowspublic static void main(String[] args) {Thread thread1 = new Thread(new Runnable() {@SneakyThrowspublic void run() {for (int i = 1000; i <= 1500; i++) {System.out.println(i);}System.out.println("子線程執行完畢!");}});thread1.start();thread1.join();for (int i = 0; i <= 50; i++) {System.out.println(i);}}面試題順序執行T1,T2,T3
現有T1,T2,T3三個線程,怎么保證T2在T1執行完后執行,T3在T2執行完后執行?
@SneakyThrowspublic static void main(String[] args) {final Thread thread1 = new Thread(new Runnable() {public void run() {for (int i = 0; i <= 10; i++) {System.out.println(i);}System.out.println("子線程1執行完畢!");}});final Thread thread2 = new Thread(new Runnable() {@SneakyThrowspublic void run() {thread1.join();for (int i = 11; i <= 20; i++) {System.out.println(i);}System.out.println("子線程2執行完畢!");}});Thread thread3 = new Thread(new Runnable() {@SneakyThrowspublic void run() {thread2.join();for (int i = 21; i <= 30; i++) {System.out.println(i);}System.out.println("子線程3執行完畢!");}});thread1.start();thread2.start();thread3.start();}案例多線程分批處理數據
端口掃描
public void threadScanPort() {ExecutorService executorService = Executors.newFixedThreadPool(100);portCount.set(0);int totalThreadNum = 100;for (int n = 0; n <= totalThreadNum; n++) {executorService.execute(new ScanHandler(n, totalThreadNum));}} class ScanHandler implements Runnable {//用于端口掃描的總共線程數private int totalThreadNum;// 線程號private int threadNo;public ScanHandler(int threadNo, int totalThreadNum) {this.totalThreadNum = totalThreadNum;this.threadNo = threadNo;}@Overridepublic void run() {int startPort = Integer.parseInt(startPortField.getText());int endPort = Integer.parseInt(endPortField.getText());String host = targetIp.getText();//startPort和endPort為成員變量,表示需要掃描的起止端口for (int port = startPort + threadNo; port <= endPort; port = port + totalThreadNum) {try {Socket socket = new Socket();socket.connect(new InetSocketAddress(host, port), 200);socket.close();String msg = "端口 " + port + " is open\n";Platform.runLater(() -> {taDisplay.appendText(msg);});} catch (IOException e) {System.out.println(port + "is close");}portCount.incrementAndGet();//掃描的端口數+1}if (portCount.get() == (endPort - startPort + 1)) {portCount.incrementAndGet();//加1,使得不再輸出下面的線程掃描結束的信息Platform.runLater(() -> {taDisplay.appendText("\n----------------多線程掃描結束--------------------\n");});}}}總結
以上是生活随笔為你收集整理的闭关修炼(一)多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python用递归方式实现最大公约数_P
- 下一篇: 大华网络摄像头通过gstreamer 获