日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

【Java多线程】轻松搞定Java多线程(一)

發(fā)布時(shí)間:2023/12/14 java 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Java多线程】轻松搞定Java多线程(一) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

輕松搞定Java多線程(一)

  • Java多線程詳解(一)
    • 1、 線程簡(jiǎn)介
    • 2、線程的創(chuàng)建
      • 2.1 三種創(chuàng)建方式
      • 2.2 Thread
      • 2.3 實(shí)現(xiàn)Runnable
        • 2.3.1 初識(shí)并發(fā)問題
        • 2.3.2 案例:龜兔賽跑
      • 2.4 實(shí)現(xiàn)Callable接口
    • 3、靜態(tài)代理模式
    • 4、Lambda表達(dá)式
      • 4.1 推導(dǎo)lambda表達(dá)式
      • 4.2 簡(jiǎn)化lambda表達(dá)式

Java多線程詳解(一)

1、 線程簡(jiǎn)介

  • 進(jìn)程:執(zhí)行程序的一次執(zhí)行過程
  • 通常在一個(gè)進(jìn)程中可以包含若干個(gè)線程,當(dāng)然一個(gè)進(jìn)程中至少有一個(gè)線程,不然沒有存在的意義。線程是CPU調(diào)度和執(zhí)行的單位。
  • 注意:很多多線程是模擬出來的,真正的多線程是指有多個(gè)cpu,即多核。如果是模擬出來的多線程,即在一個(gè)cpu的情況下,在同一個(gè)時(shí)間點(diǎn),cpu只能執(zhí)行一個(gè)代碼,因?yàn)榍袚Q的很快。所以有同時(shí)執(zhí)行的錯(cuò)覺。

    • 線程就是獨(dú)立的執(zhí)行路徑;
    • 在程序運(yùn)行時(shí),即使沒有自己創(chuàng)建線程,后臺(tái)也會(huì)有多個(gè)線程,如主線程,gc線程;
    • main()稱之為主線程,為系統(tǒng)的入口,用于執(zhí)行整個(gè)程序;
    • 在一個(gè)進(jìn)程中,如果開辟了多個(gè)線程,線程的運(yùn)行由調(diào)度器安排調(diào)度,調(diào)度器是與操作系統(tǒng)緊密相關(guān)的,先后順序是不能人為干預(yù)的;
    • 對(duì)同一份資源操作時(shí),會(huì)存在資源搶奪的問題,需要加入并發(fā)控制;
    • 線程會(huì)帶來額外的開銷,如cpu調(diào)度時(shí)間,并發(fā)控制開銷;
    • 每個(gè)線程在自己的工作內(nèi)存交互,內(nèi)存控制不當(dāng)會(huì)造成數(shù)據(jù)不一致。
  • 普通方法調(diào)用和多線程
  • 2、線程的創(chuàng)建

    2.1 三種創(chuàng)建方式

  • Thread class ==> 繼承Thread類
  • Runnable接口 ==> 實(shí)現(xiàn)Runnable接口
  • Callable接口 ==> 實(shí)現(xiàn)Callable接口
  • 2.2 Thread

    • 自定義線程類繼承Thread類
    • 重寫run()方法,編寫線程執(zhí)行體
    • 創(chuàng)建線程對(duì)象,調(diào)用start()方法啟動(dòng)線程
    /*** 創(chuàng)建線程方法一:* 繼承Thread類,重寫run()方法,調(diào)用start()方法開啟線程*//*** 總結(jié):注意,線程開啟不一定立即執(zhí)行,由cpu調(diào)度執(zhí)行*/ public class TestThread1 extends Thread{@Overridepublic void run() {// run方法線程體for (int i = 0; i < 200; i++) {System.out.println("新線程" + i);}}public static void main(String[] args) {// main線程,主線程// 創(chuàng)建一個(gè)線程對(duì)象TestThread1 testThread1 = new TestThread1();// 調(diào)用start()方法開啟線程testThread1.start();for (int i = 0; i < 200; i++) {System.out.println("主線程" + i);}} } import org.apache.commons.io.FileUtils;import java.io.File; import java.io.IOException; import java.net.URL;/*** 練習(xí)Thread,實(shí)現(xiàn)多線程同步下載圖片* (需要用到commons-io.jar)*/ public class TestThread2 extends Thread{/*** 圖片地址*/private String url;/*** 保存的文件名*/private String name;public TestThread2(String url, String name) {this.url = url;this.name = name;}/*** 下載圖片線程的執(zhí)行體*/@Overridepublic void run() {WebDownloader webDownloader = new WebDownloader();webDownloader.download(url, name);System.out.println("下載了文件名為:" + name + "的文件");}public static void main(String[] args) {TestThread2 t1 = new TestThread2("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png", "百度.png");TestThread2 t2 = new TestThread2("https://mat1.gtimg.com/pingjs/ext2020/qqindex2018/dist/img/qq_logo_2x.png", "騰訊.png");TestThread2 t3 = new TestThread2("https://img.alicdn.com/tfs/TB1Ly5oS3HqK1RjSZFPXXcwapXa-238-54.png", "阿里云.png");t1.start();t2.start();t3.start();} }/*** 下載器*/ class WebDownloader {/*** 下載方法*/public void download(String url, String name) {try {FileUtils.copyURLToFile(new URL(url), new File(name));} catch (IOException e) {e.printStackTrace();System.out.println("IO異常,download方法出現(xiàn)問題");}} }

    執(zhí)行結(jié)果:

    2.3 實(shí)現(xiàn)Runnable

    • 定義MyRunnable類實(shí)現(xiàn)Runable接口
    • 實(shí)現(xiàn)run()方法,編寫程序執(zhí)行體
    • 創(chuàng)建線程對(duì)象,調(diào)用start()方法啟動(dòng)線程
    /*** 創(chuàng)建線程方式2:* 實(shí)現(xiàn)Runnable接口,重寫run()方法,執(zhí)行線程需要丟入Runnable接口的實(shí)現(xiàn)類,調(diào)用start()方法*/ public class TestThread3 implements Runnable {@Overridepublic void run() {// run方法線程體for (int i = 0; i < 200; i++) {System.out.println("新線程" + i);}}public static void main(String[] args) {/*** 創(chuàng)建Runnable接口的實(shí)現(xiàn)類對(duì)象*/TestThread3 testThread3 = new TestThread3();/*** 創(chuàng)建線程對(duì)象,通過線程對(duì)象來開啟我們的線程(代理)*/new Thread(testThread3).start();for (int i = 0; i < 200; i++) {System.out.println("主線程" + i);}} }

    小結(jié):

    • 繼承Thread類
      • 子類繼承Thread類具備多線程能力
      • 啟動(dòng)線程:子類對(duì)象.start();
      • 不建議使用:避免OOP單繼承局限性
    • 實(shí)現(xiàn)Runnable接口
      • 實(shí)現(xiàn)接口Runnable具有多線程的能力
      • 啟動(dòng)線程:傳入目標(biāo)對(duì)象+Thread對(duì)象.start();
      • 推薦使用:避免單繼承局限性,靈活方便,方便同一個(gè)對(duì)象被多個(gè)線程使用

    2.3.1 初識(shí)并發(fā)問題

    /*** 多個(gè)線程同時(shí)操作一個(gè)對(duì)象* 買火車票的例子*//*** 發(fā)現(xiàn)問題:* 多個(gè)線程操作同一個(gè)資源的情況下,線程不安全,數(shù)據(jù)紊亂*/ public class TestThread4 implements Runnable {/*** 票數(shù)*/private int ticketsNums = 20;@Overridepublic void run() {while (true) {if (ticketsNums <= 0) {break;}/*** 模擬延時(shí)*/try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "拿到了" + ticketsNums-- + "票");}}public static void main(String[] args) {TestThread4 ticket = new TestThread4();new Thread(ticket, "小明").start();new Thread(ticket, "老師").start();new Thread(ticket, "黃牛").start();} }

    2.3.2 案例:龜兔賽跑

    /*** 模擬龜兔賽跑*/ public class Race implements Runnable {/*** 勝利者*/private static String winner;@Overridepublic void run() {for (int i = 0; i <= 100; i++) {/*** 模擬兔子睡覺*/if (Thread.currentThread().getName().equals("兔子") && i%10 == 0) {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}/*** 判斷比賽是否結(jié)束*/boolean flag = gameOver(i);/*** 如果比賽結(jié)束,退出程序*/if (flag) {break;}System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");}}/*** 判斷是否完成比賽*/private boolean gameOver(int steps) {/*** 判斷是否有勝利者*/if (winner != null) {return true;} else if (steps >= 100){winner = Thread.currentThread().getName();System.out.println("winner is " + winner);return true;}return false;}public static void main(String[] args) {Race race = new Race();new Thread(race, "兔子").start();new Thread(race, "烏龜").start();} }

    2.4 實(shí)現(xiàn)Callable接口

  • 實(shí)現(xiàn)Callable接口,需要返回值類型
  • 重寫call方法,需要拋出異常
  • 創(chuàng)建目標(biāo)對(duì)象
  • 創(chuàng)建執(zhí)行服務(wù):ExecutorService ser = Executors.newFixedThreadPool(1);
  • 提交執(zhí)行:Future< Boolean > result1 = ser.submit(t1);
  • 獲取結(jié)果:boolean r1 = result1.get()
  • 關(guān)閉服務(wù):ser.shutdownNow();
  • /*** 線程創(chuàng)建方式三:實(shí)現(xiàn)Callable接口*/ public class TestCallable implements Callable<Boolean> {/*** 圖片地址*/private String url;/*** 保存的文件名*/private String name;public TestCallable(String url, String name) {this.url = url;this.name = name;}/*** 下載圖片線程的執(zhí)行體* @return* @throws Exception*/@Overridepublic Boolean call() throws Exception {WebDownloader webDownloader = new WebDownloader();webDownloader.download(url, name);System.out.println("下載了文件名為:" + name + "的文件");return true;}public static void main(String[] args) throws ExecutionException, InterruptedException {TestCallable t1 = new TestCallable("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png", "百度.png");TestCallable t2 = new TestCallable("https://mat1.gtimg.com/pingjs/ext2020/qqindex2018/dist/img/qq_logo_2x.png", "騰訊.png");TestCallable t3 = new TestCallable("https://img.alicdn.com/tfs/TB1Ly5oS3HqK1RjSZFPXXcwapXa-238-54.png", "阿里云.png");/*** 創(chuàng)建執(zhí)行服務(wù)*/ExecutorService service = Executors.newFixedThreadPool(3);/*** 提交執(zhí)行*/Future<Boolean> result1 = service.submit(t1);Future<Boolean> result2 = service.submit(t2);Future<Boolean> result3 = service.submit(t3);/*** 獲取結(jié)果*/boolean rs1 = result1.get();boolean rs2 = result2.get();boolean rs3 = result3.get();/*** 關(guān)閉服務(wù)*/service.shutdownNow();} }/*** 下載器*/ class WebDownloader {/*** 下載方法*/public void download(String url, String name) {try {FileUtils.copyURLToFile(new URL(url), new File(name));} catch (IOException e) {e.printStackTrace();System.out.println("IO異常,download方法出現(xiàn)問題");}} }

    Callable的好處:

  • 可以定義返回值
  • 可以拋出異常
  • 3、靜態(tài)代理模式

    靜態(tài)代理模式總結(jié):

    真實(shí)對(duì)象和代理對(duì)象都要實(shí)現(xiàn)同一個(gè)接口

    代理對(duì)象代理真實(shí)角色

    好處

    代理對(duì)象可以做很多真實(shí)對(duì)象做不了的事情

    真實(shí)對(duì)象專注做自己的事情

    /*** Jack結(jié)婚的例子,婚慶公司幫助Jack結(jié)婚*/ public class StaticProxy {public static void main(String[] args) {WeddingCompany weddingCompany = new WeddingCompany(new Jack());weddingCompany.HappyMarry();}}interface Marry {void HappyMarry(); }/*** 真實(shí)角色*/ class Jack implements Marry {@Overridepublic void HappyMarry() {System.out.println("Jack要結(jié)婚了");} }/*** 代理角色*/ class WeddingCompany implements Marry {private Marry target;public WeddingCompany(Marry target) {this.target = target;}@Overridepublic void HappyMarry() {before();this.target.HappyMarry();after();}private void before() {System.out.println("結(jié)婚之前,布置現(xiàn)場(chǎng)");}private void after() {System.out.println("結(jié)婚之后,收拾東西");} }

    4、Lambda表達(dá)式

    • 其實(shí)質(zhì)屬于函數(shù)式編程的概念
    (params) -> expression [表達(dá)式] (params) -> statement [語(yǔ)句] (params) -> {statements}
    • 為什么要使用lambda表達(dá)式
      • 避免匿名內(nèi)部類定義過多
      • 可以讓你的代碼看起了很簡(jiǎn)潔
      • 去掉了一堆沒有意義的代碼,只留下核心的邏輯
    • 函數(shù)式接口的定義:

      • 任何接口,如果只包含唯一一個(gè)抽象方法,那么它就是一個(gè)函數(shù)式接口。
      public interface Runnable {public abstract void run(); }
      • 對(duì)于函數(shù)式接口,我們可以通過lambda表達(dá)式來創(chuàng)建該接口的對(duì)象。

    4.1 推導(dǎo)lambda表達(dá)式

    /*** 推導(dǎo)lambda表達(dá)式*/ public class TestLambda1 {/*** 3.靜態(tài)內(nèi)部類*/static class Like2 implements ILike {@Overridepublic void lambda() {System.out.println("I Like Lambda2");}}public static void main(String[] args) {ILike like = new Like();like.lambda();like = new Like2();like.lambda();/*** 4.局部?jī)?nèi)部類*/class Like3 implements ILike {@Overridepublic void lambda() {System.out.println("I Like Lambda3");}}like = new Like3();like.lambda();/*** 5.匿名內(nèi)部類,沒有類的名稱,必須借助接口或者父類*/like = new ILike() {@Overridepublic void lambda() {System.out.println("I Like Lambda4");}};like.lambda();/*** 6.用lambda簡(jiǎn)化*/like = () -> {System.out.println("I Like Lambda5");};like.lambda();}/*** 1.定義一個(gè)函數(shù)式接口*/interface ILike {void lambda();}/*** 2.實(shí)現(xiàn)類*/static class Like implements ILike {@Overridepublic void lambda() {System.out.println("I Like Lambda");}} }

    4.2 簡(jiǎn)化lambda表達(dá)式

    public class TestLambda2 {public static void main(String[] args) {ILove love = new Love();love.love(1);love = (int a) -> {System.out.println("I Love Lambda-->" + a);};love.love(2);/*** 簡(jiǎn)化1:參數(shù)類型*/love = (a) -> {System.out.println("I Love Lambda-->" + a);};love.love(3);/*** 簡(jiǎn)化2:簡(jiǎn)化括號(hào)*/love = a -> {System.out.println("I Love Lambda-->" + a);};love.love(4);/*** 簡(jiǎn)化3:簡(jiǎn)化花括號(hào)*/love = a -> System.out.println("I Love Lambda-->" + a);love.love(5);} }interface ILove {void love(int a); }class Love implements ILove {@Overridepublic void love(int a) {System.out.println("I Love Lambda-->" + a);} }

    總結(jié):

  • lambda表達(dá)式只有一行代碼時(shí),可以省略花括號(hào)
  • 前提是接口為函數(shù)式接口
  • 多個(gè)參數(shù)也可以去掉參數(shù)類型,要去掉就全都去掉,必須加上括號(hào)
  • 總結(jié)

    以上是生活随笔為你收集整理的【Java多线程】轻松搞定Java多线程(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。