亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

入門Java線程基礎(chǔ)一篇就夠了

 更新時間:2021年06月18日 16:52:58   作者:Liziba  
線程是進程中的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源

簡介

線程是操作系統(tǒng)調(diào)度的最小單元,在多核環(huán)境中,多個線程能同時執(zhí)行,如果運用得當(dāng),能顯著的提升程序的性能。

一、線程初步認(rèn)識

1、什么是線程

操作系統(tǒng)運行一個程序會為其啟動一個進程。例如,啟動一個Java程序會創(chuàng)建一個Java進程?,F(xiàn)代操作系統(tǒng)調(diào)度的最小單元是線程,線程也稱為輕量級進程(Light Weight Process),一個進程中可以創(chuàng)建一個到多個線程,線程擁有自己的計數(shù)器、堆棧和局部變量等屬性,并且能訪問共享的內(nèi)存變量。處理器會通過快速切換這些線程,來執(zhí)行程序。 ​

2、Java本身就是多線程

示例代碼:

package com.lizba.p2;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Arrays;
/**
 * <p>
 *
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/13 23:03
 */
public class MultiThread {
    public static void main(String[] args) {
        // 獲取Java線程管理MXBean
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        // 獲取線程和線程堆棧信息;
        // boolean lockedMonitors = false  不需要獲取同步的monitor信息;
        // boolean lockedSynchronizers = false  不需要獲取同步的synchronizer信息
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
        // 打印線程ID和線程name
        Arrays.stream(threadInfos).forEach(threadInfo -> {
            System.out.println("[" + threadInfo.getThreadId() + "]" + threadInfo.getThreadName());
        });
    }
}

輸出結(jié)果(不一定一致):

[6]Monitor Ctrl-Break // idea中特有的線程(不用管)

[5]Attach Listener // JVM進程間的通信線程

[4]Signal Dispatcher // 分發(fā)處理發(fā)送給JVM信號的線程

[3]Finalizer // 調(diào)用對象的finalizer線程

[2]Reference Handler // 清楚Reference的線程

[1]main // main線程,用戶程序入口

總結(jié):從輸出結(jié)果不難看出,Java程序本身就是多線程的。它不僅僅只有一個main線程在運行,而是main線程和其他多個線程在同時運行。

3、為什么要使用多線程

使用多線程的好處如下:

1.更多處理器核心

計算機處理器核心數(shù)增多,由以前的高主頻向多核心技術(shù)發(fā)展,現(xiàn)在的計算機更擅長于并行計算,因此如何充分利用多核心處理器是現(xiàn)在的主要問題。線程是操作系統(tǒng)調(diào)度的最小單元,一個程序作為一個進程來運行,它會創(chuàng)建多個線程,而一個線程在同一時刻只能運行在一個處理器上。因此一個進程如果能使用多線程計算,將其計算邏輯分配到多個處理器核心上,那么相比單線程運行將會有更顯著的性能提升。

2.更快響應(yīng)時間

在復(fù)雜業(yè)務(wù)場景中,我們可以將非強一致性關(guān)聯(lián)的業(yè)務(wù)派發(fā)給其他線程處理(或者使用消息隊列)。這樣可以減少應(yīng)用響應(yīng)用戶請求的時間

3.更好的編程模型

合理使用Java的提供的多線程編程模型,能使得程序員更好的解決問題,而不需要過于復(fù)雜的考慮如何將其多線程化。

4、線程的優(yōu)先級

現(xiàn)代操作系統(tǒng)基本采用的是時間片分配的方式來調(diào)度線程,也就是操作系統(tǒng)將CPU的運行分為一個個時間片,線程會分配的若干時間片,當(dāng)線程時間片用完了,就會發(fā)生線程調(diào)度等待下次時間片的分配。線程在一次CPU調(diào)度中能執(zhí)行多久,取決于所分時間片的多少,而線程優(yōu)先級就是決定線程需要多或者少分配一些處理器資源的線程屬性。在Java線程中,線程的優(yōu)先級的可設(shè)置范圍是1-10,默認(rèn)優(yōu)先級是5,理論上優(yōu)先級高的線程分配時間片數(shù)量要優(yōu)先于低的線程(部分操作系統(tǒng)這個設(shè)置是不生效的); ​

示例代碼

package com.lizba.p2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
 * <p>
 *      線程優(yōu)先級設(shè)置
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 12:03
 */
public class Priority {
    /** 線程執(zhí)行流程控制開關(guān) */
    private static volatile boolean notStart = true;
    /** 線程執(zhí)行流程控制開關(guān) */
    private static volatile boolean notEnd = true;
    public static void main(String[] args) throws InterruptedException {
        List<Job> jobs = new ArrayList<>();
        // 設(shè)置5個優(yōu)先級為1的線程,設(shè)置5個優(yōu)先級為10的線程
        for (int i = 0; i < 10; i++) {
            int priority = i < 5 ? Thread.MIN_PRIORITY : Thread.MAX_PRIORITY;
            Job job = new Job(priority);
            jobs.add(job);
            Thread thread = new Thread(job, "Thread:" + i);
            thread.setPriority(priority);
            thread.start();
        }
        notStart = false;
        TimeUnit.SECONDS.sleep(10);
        notEnd = false;
        jobs.forEach(
                job -> System.out.println("Job priority : " + job.priority + ", Count : " + job.jobCount)
        );
    }

    /**
     * 通過Job來記錄線程的執(zhí)行次數(shù)和優(yōu)先級
     */
    static class Job implements Runnable {
        private int priority;
        private long jobCount;
        public Job(int priority) {
            this.priority = priority;
        }
        @Override
        public void run() {
            while (notStart) {
                // 讓出CPU時間片,等待下次調(diào)度
                Thread.yield();
            }
            while (notEnd) {
                // 讓出CPU時間片,等待下次調(diào)度
                Thread.yield();
                jobCount++;
            }
        }
    }
}

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

在這里插入圖片描述

從輸出結(jié)果上來看,優(yōu)先級為1的線程和優(yōu)先級為10的線程執(zhí)行的次數(shù)非常相近,因此這表明程序正確性是不能依賴線程的優(yōu)先級高低的。

5、線程的狀態(tài)

線程的生命周期如下:

狀態(tài)名稱 說明
NEW 初始狀態(tài),線程被構(gòu)建,并未調(diào)用start()方法
RUNNABLE 運行狀態(tài),Java線程將操作系統(tǒng)中的就緒和運行兩種狀態(tài)統(tǒng)稱為“運行中”
BLOCKED 阻塞狀態(tài),線程阻塞于鎖
WAITING 等待狀態(tài),線程進入等待狀態(tài),進入該狀態(tài)表示當(dāng)前線程需要等待其他線程作出一些特定動作(通知或中斷)
TIME_WAITING 超時等待,先比WAITING可以在指定的時間內(nèi)自行返回
TERMINATED 終止?fàn)顟B(tài),表示當(dāng)前線程已經(jīng)執(zhí)行完畢

通過代碼來查看Java線程的狀態(tài)

代碼示例:

package com.lizba.p2;
import java.util.concurrent.TimeUnit;
/**
 * <p>
 *      睡眠指定時間工工具類
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 13:27
 */
public class SleepUtil {
    public static final void sleepSecond(long seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.lizba.p2;
/**
 * <p>
 *      線程狀態(tài)示例代碼
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 13:25
 */
public class ThreadStateDemo {
    public static void main(String[] args) {
        // TimeWaiting
        new Thread(new TimeWaiting(), "TimeWaitingThread").start();
        // Waiting
        new Thread(new Waiting(), "WaitingThread").start();
        // Blocked1和Blocked2一個獲取鎖成功,一個獲取失敗
        new Thread(new Blocked(), "Blocked1Thread").start();
        new Thread(new Blocked(), "Blocked2Thread").start();
    }
    // 線程不斷的進行睡眠
    static class TimeWaiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                SleepUtil.sleepSecond(100);
            }
        }
    }
    // 線程等待在Waiting.class實例上
    static class Waiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (Waiting.class) {
                    try {
                        Waiting.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    // 該線程Blocked.class實例上加鎖,不會釋放該鎖
    static class Blocked implements Runnable {
        @Override
        public void run() {
            synchronized (Blocked.class) {
                while (true) {
                    SleepUtil.sleepSecond(100);
                }
            }
        }
    }
}

使用JPS查看Java進程

在這里插入圖片描述

查看示例代碼ThreadStateDemo進程ID是2576,鍵入jstack 2576查看輸出:

在這里插入圖片描述

整理輸出結(jié)果在這里插入圖片描述

線程名稱 線程狀態(tài)
Blocked2Thread BLOCKED (on object monitor),阻塞在獲取Blocked.class的鎖上
Blocked1Thread TIMED_WAITING (sleeping)
WaitingThread WAITING (on object monitor)
TimeWaitingThread TIMED_WAITING (sleeping)

總結(jié):線程在自身生命周期中不是規(guī)定處于某一個狀態(tài),而是隨著代碼的執(zhí)行在不同的狀態(tài)之間進行切換。 ​

Java線程的狀態(tài)變化圖如下

在這里插入圖片描述

Java線程狀態(tài)變遷圖

總結(jié):

  • 線程創(chuàng)建后,調(diào)用start()方法開始運行
  • 線程執(zhí)行wait()方法后,線程進入等待狀態(tài),進入等待的線程需要依靠其他線程才能夠返回到運行狀態(tài)
  • 超時等待相當(dāng)于在等待狀態(tài)的基礎(chǔ)上增加了超時限制,達到設(shè)置的超時時間后返回到運行狀態(tài)
  • 線程執(zhí)行同步方法或代碼塊時,未獲取到鎖的線程,將會進入到阻塞狀態(tài)。
  • 線程執(zhí)行完Runnable的run()方法之后進入到終止?fàn)顟B(tài)
  • 阻塞在Java的concurrent包中Lock接口的線程是等待狀態(tài),因為Lock接口阻塞的實現(xiàn)使用的是Daemon線程

6、Daemon線程

簡介:

Daemon線程是一種支持型線程,它的主要作用是程序中后臺調(diào)度和支持性工作。當(dāng)一個Java虛擬機中不存在非Daemon線程的時候,Java虛擬機將會退出。Daemon線程需要在啟動之前設(shè)置,不能在啟動之后設(shè)置。

設(shè)置方式

Thread.setDaemon(true)

需要特別注意的點

Daemon線程被用作支持性工作的完成,但是在Java虛擬機退出時Daemon線程的finally代碼塊不一定執(zhí)行。

示例代碼

package com.lizba.p2;
/**
 * <p>
 *      DaemonRunner線程
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 19:50
 */
public class DaemonRunner implements Runnable{
    @Override
    public void run() {
        try {
            SleepUtil.sleepSecond(100);
        } finally {
            System.out.println("DaemonRunner finally run ...");
        }
    }
}

測試

package com.lizba.p2;
/**
 * <p>
 *
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 19:59
 */
public class DaemonTest {
    public static void main(String[] args) {
        Thread t = new Thread(new DaemonRunner(), "DaemonRunner");
        t.setDaemon(true);
        t.start();
    }
}

輸出結(jié)果

在這里插入圖片描述

總結(jié)

不難發(fā)現(xiàn),DaemonRunner的run方法的finally代碼塊并沒有執(zhí)行,這是因為,當(dāng)Java虛擬機中已經(jīng)沒有非Daemon線程時,虛擬機會立即退出,虛擬機中的所以daemon線程需要立即終止,所以線程DaemonRunner會被立即終止,finally并未執(zhí)行。

二、線程啟動和終止

1、構(gòu)造線程

運行線程之前需要構(gòu)造一個線程對象,線程對象在構(gòu)造的時候需要設(shè)置一些線程的屬性,這些屬性包括線程組、線程的優(yōu)先級、是否是daemon線程、線程名稱等信息。

代碼示例:

來自java.lang.Thread

  /**     * Initializes a Thread.     *     * @param g the Thread group     * @param target the object whose run() method gets called     * @param name the name of the new Thread     * @param stackSize the desired stack size for the new thread, or     *        zero to indicate that this parameter is to be ignored.     * @param acc the AccessControlContext to inherit, or     *            AccessController.getContext() if null     * @param inheritThreadLocals if {@code true}, inherit initial values for     *            inheritable thread-locals from the constructing thread     */    private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) {        if (name == null) {            throw new NullPointerException("name cannot be null");        }// 設(shè)置線程名稱        this.name = name;// 當(dāng)前線程設(shè)置為該線程的父線程        Thread parent = currentThread();        SecurityManager security = System.getSecurityManager();        if (g == null) {            if (security != null) {                g = security.getThreadGroup();            }            if (g == null) {                g = parent.getThreadGroup();            }        }        g.checkAccess();        if (security != null) {            if (isCCLOverridden(getClass())) {                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);            }        }        g.addUnstarted();// 設(shè)置線程組        this.group = g;        // 將daemon屬性設(shè)置為父線程的對應(yīng)的屬性        this.daemon = parent.isDaemon();        // 將prority屬性設(shè)置為父線程的對應(yīng)的屬性        this.priority = parent.getPriority();        if (security == null || isCCLOverridden(parent.getClass()))            this.contextClassLoader = parent.getContextClassLoader();        else            this.contextClassLoader = parent.contextClassLoader;        this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext();        this.target = target;        setPriority(priority);        // 復(fù)制父線程的InheritableThreadLocals屬性        if (inheritThreadLocals && parent.inheritableThreadLocals != null)            this.inheritableThreadLocals =                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);        /* Stash the specified stack size in case the VM cares */        this.stackSize = stackSize;       // 設(shè)置一個線程id        tid = nextThreadID();    }

總結(jié)

在上述代碼中,一個新構(gòu)建的線程對象時由其parent線程來分配空間的,而child繼承了parent是否為Daemon、優(yōu)先級和加載資源的contextClassLoader以及可繼承的ThreadLocal,同時會分配一個唯一的ID來標(biāo)志線程。此時一個完整的能夠運行的線程對象就初始化好了,在堆內(nèi)存中等待運行。 ​

2、什么是線程中斷

中斷可以理解為線程的一個標(biāo)識位屬性,它表示一個運行中的線程是否被其他線程進行了中斷操作。線程通過檢查自身是否被中斷來進行響應(yīng),線程通過方法isInterrupted()來進行判斷是否被中斷,也可以通過調(diào)用靜態(tài)方法Thread.interrupted()對當(dāng)前線程的中斷標(biāo)志位進行復(fù)位。如下情況不能準(zhǔn)確判斷線程是否被中斷過:

線程已經(jīng)終止運行,即使被中斷過,isInterrupted()方法也會返回false方法拋出InterruptedException異常,即使被中斷過,調(diào)用isInterrupted()方法將會返回false,這是因為拋出InterruptedException之前會清除中斷標(biāo)志。

示例代碼:

package com.lizba.p2;
/**
 * <p>
 *      線程中斷示例代碼
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 20:36
 */
public class Interrupted {
    public static void main(String[] args) {
        // sleepThread不停的嘗試睡眠
        Thread sleepThread = new Thread(new SleepRunner(), "sleepThread");
        sleepThread.setDaemon(true);
        // busyThread
        Thread busyThread = new Thread(new BusyRunner(), "busyThread");
        busyThread.setDaemon(true);
        // 啟動兩個線程
        sleepThread.start();
        busyThread.start();
        // 休眠5秒,讓sleepThread和busyThread運行充分
        SleepUtil.sleepSecond(5);
        // 中斷兩個線程
        sleepThread.interrupt();
        busyThread.interrupt();
        System.out.println("SleepThread interrupted is " + sleepThread.isInterrupted());
        System.out.println("BusyThread interrupted is " + busyThread.isInterrupted());
        // 睡眠主線程,防止daemon線程退出
        SleepUtil.sleepSecond(2);
    }
    static class SleepRunner implements Runnable {
        @Override
        public void run() {
            while (true) {
                SleepUtil.sleepSecond(10);
            }
        }
    }
    static class BusyRunner implements Runnable {
        @Override
        public void run() {
            while (true) {}
        }
    }
}

查看運行結(jié)果:

在這里插入圖片描述

總結(jié)

拋出InterruptedException的是sleepThread線程,雖然兩者都被中斷過,但是sleepThread線程的中斷標(biāo)志返回的是false,這是因為TimeUnit.SECONDS.sleep(seconds)會拋出InterruptedException異常,拋出異常之前,sleepThread線程的中斷標(biāo)志被清除了。但是,busyThread一直在運行沒有拋出異常,中斷位沒有被清除。 ​

3、suspend()、resume()和stop()

舉例:

線程這三個方法,相當(dāng)于QQ音樂播放音樂時的暫停、恢復(fù)和停止操作。(注意這些方法已經(jīng)過期了,不建議使用。)

示例代碼

package com.lizba.p2;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
 * <p>
 *      線程過期方法示例
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 20:57
 */
public class Deprecated {

    static DateFormat format = new SimpleDateFormat("HH:mm:ss");
    public static void main(String[] args) {
        Thread printThread = new Thread(new PrintThread(), "PrintThread");
        printThread.start();
        SleepUtil.sleepSecond(3);
        // 暫停printThread輸出
        printThread.suspend();
        System.out.println("main suspend PrintThread at " + format.format(new Date()));
        SleepUtil.sleepSecond(3);
        // 恢復(fù)printThread輸出
        printThread.resume();
        System.out.println("main resume PrintThread at " + format.format(new Date()));
        SleepUtil.sleepSecond(3);
        // 終止printThread輸出
        printThread.stop();
        System.out.println("main stop PrintThread at " + format.format(new Date()));
        SleepUtil.sleepSecond(3);
    }

    static class PrintThread implements Runnable {
        @Override
        public void run() {
           while (true) {
               System.out.println(Thread.currentThread().getName() + "Run at "
               + format.format(new Date()));
               SleepUtil.sleepSecond(1);
           }
        }
    }
}

輸出結(jié)果

在這里插入圖片描述

總結(jié)

上述代碼執(zhí)行輸出的結(jié)果,與API說明和我們的預(yù)期完成一致,但是看似正確的代碼卻隱藏這很多問題。

存在問題

  • suspend()方法調(diào)用后不會釋放已占有的資源(比如鎖),可能會導(dǎo)致死鎖
  • stop()方法在終結(jié)一個線程時不能保證資源的正常釋放,可能會導(dǎo)致程序處于不確定的工作狀態(tài)

4、正確的終止線程

調(diào)用線程的interrupt()方法使用一個Boolean類型的變量來控制是否停止任務(wù)并終止線程

示例代碼

package com.lizba.p2;
/**
 * <p>
 *      標(biāo)志位終止線程示例代碼
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/6/14 21:17
 */
public class ShutDown {
    public static void main(String[] args) {
        Runner one = new Runner();
        Thread t = new Thread(one, "CountThread");
        t.start();
        SleepUtil.sleepSecond(1);
        t.interrupt();
        Runner two = new Runner();
        t = new Thread(two, "CountThread");
        t.start();
        SleepUtil.sleepSecond(1);
        two.cancel();
    }

    private static class Runner implements Runnable {
        private long i;
        private volatile boolean on = true;
        @Override
        public void run() {
            while (on && !Thread.currentThread().isInterrupted()) {
                i++;
            }
            System.out.println("Count i = " +i);
        }
        /**
         * 關(guān)閉
         */
        public void cancel() {
            on = false;
        }
    }
}

輸出結(jié)果:

在這里插入圖片描述

總結(jié):

main線程通過中斷操作和cancel()方法均可使CountThread得以終止。這兩種方法終止線程的好處是能讓線程在終止時有機會去清理資源。做法更加安全和優(yōu)雅。希望大家可以多多關(guān)注腳本之家的更多內(nèi)容! ​

相關(guān)文章

  • Java如何通過"枚舉的枚舉"表示二級分類的業(yè)務(wù)場景

    Java如何通過"枚舉的枚舉"表示二級分類的業(yè)務(wù)場景

    這篇文章主要介紹了Java如何通過"枚舉的枚舉"表示二級分類的業(yè)務(wù)場景問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • JAVA中三種常用的循環(huán)語句詳解

    JAVA中三種常用的循環(huán)語句詳解

    這篇文章主要介紹了JAVA中三種常用的循環(huán)語句詳解,包括格式和執(zhí)行流程,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • SpringBoot實現(xiàn)過濾器和攔截器的方法

    SpringBoot實現(xiàn)過濾器和攔截器的方法

    大家應(yīng)該都曉得實現(xiàn)過濾器需要實現(xiàn)?javax.servlet.Filter?接口,而攔截器會在處理指定請求之前和之后進行相關(guān)操作,配置攔截器需要兩步,本文通過實例代碼給大家介紹SpringBoot?過濾器和攔截器的相關(guān)知識,感興趣的朋友一起看看吧
    2022-11-11
  • 使用Spring boot + jQuery上傳文件(kotlin)功能實例詳解

    使用Spring boot + jQuery上傳文件(kotlin)功能實例詳解

    本文通過實例代碼給大家介紹了使用Spring boot + jQuery上傳文件(kotlin) 功能,需要的朋友可以參考下
    2017-07-07
  • Java不要再使用!=null判空了!

    Java不要再使用!=null判空了!

    這篇文章主要給大家介紹了關(guān)于Java不要再使用!=null判空的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • websocket在springboot+vue中的使用教程

    websocket在springboot+vue中的使用教程

    這篇文章主要介紹了websocket在springboot+vue中的使用教程,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • java實現(xiàn)多設(shè)備同時登錄或強制下線

    java實現(xiàn)多設(shè)備同時登錄或強制下線

    本文主要介紹了java實現(xiàn)多設(shè)備同時登錄或強制下線,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • SpringBoot啟動嵌入式Tomcat的實現(xiàn)步驟

    SpringBoot啟動嵌入式Tomcat的實現(xiàn)步驟

    本文主要介紹了淺談SpringBoot如何啟動嵌入式Tomcat,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java獲取中文拼音、中文首字母縮寫和中文首字母的示例

    Java獲取中文拼音、中文首字母縮寫和中文首字母的示例

    本文主要介紹了Java獲取中文拼音、中文首字母縮寫和中文首字母,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2016-10-10
  • 詳解java創(chuàng)建一個女朋友類(對象啥的new一個就是)==建造者模式,一鍵重寫

    詳解java創(chuàng)建一個女朋友類(對象啥的new一個就是)==建造者模式,一鍵重寫

    這篇文章主要介紹了java建造者模式一鍵重寫,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評論