最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中該如何優(yōu)雅的使用線程池詳解

 更新時間:2021年12月15日 09:10:02   作者:細思極恐  
在java開發(fā)中我們對“池”的概念并不陌生,常見的有數據庫連接池、線程池、對象池、常量池等等,其作用基本上就是避免頻繁的創(chuàng)建和回收,造成資源浪費,線程池也不例外,這篇文章主要給大家介紹了關于Java中該如何優(yōu)雅的使用線程池的相關資料,需要的朋友可以參考下

為什么要用線程池?

線程是不是越多越好?

  1. 線程在java中是一個對象,更是操作系統(tǒng)的資源,線程創(chuàng)建、銷毀需要時間。如果創(chuàng)建時間+小會時間>執(zhí)行任務時間就很不合算。
  2. java對象占用堆內存,操作系統(tǒng)線程占用系統(tǒng)內存,根據jvm規(guī)范,一個線程默認最大棧大小1M,這個??臻g是需要從系統(tǒng)內存中分配的。線程過多,會消耗很多的內存。
  3. 操作系統(tǒng)需要頻繁切換線程上下文(每個線都想被運行),影響性能。

線程池的推出,就是為了方便邊的控制線程數量。

線程池

線程池基本概念

線程池包括以下四個基本組成部分:

  1. 線程池管理器:用于創(chuàng)建并管理線程池,包括創(chuàng)建線程池,銷毀線程池,添加新任務;
  2. 工作線程:線程池中線程,在沒有任務時處于等待狀態(tài),可以循環(huán)的執(zhí)行任務;
  3. 任務接口:每個任務必須實現(xiàn)的借口,以供工作線程調度任務的執(zhí)行,它主要規(guī)定了任務的入口,任務執(zhí)行完后的收尾工作,任務的執(zhí)行狀態(tài)等;
  4. 任務隊列:用于存放沒有處理的任務。提供一種緩沖機制。

線程池接口定義和實現(xiàn)類

可以認為ScheduledThreadPoolExector是最豐富的實現(xiàn)類。

ExecutorService

public interface ExecutorService extends Executor {
    /**
     * 優(yōu)雅關閉線程池,之前提交的任務將被執(zhí)行,但是不會接受新的任務。
     */
    void shutdown();

    /**
     * 嘗試停止所有正在執(zhí)行的任務,停止等待任務的處理,并返回等待執(zhí)行任務的列表。
     */
    List<Runnable> shutdownNow();

    /**
     * 如果此線程池已關閉,則返回true.
     */
    boolean isShutdown();

    /**
     * 如果關閉后的所有任務都已完成,則返回true
     */
    boolean isTerminated();

    /**
     * 監(jiān)測ExecutorService是否已經關閉,直到所有任務完成執(zhí)行,或超時發(fā)生,或當前線程被中斷。
     */
    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * 提交一個用于執(zhí)行的Callable返回任務,并返回一個Future,用于獲取Callable執(zhí)行結果。
     */
    <T> Future<T> submit(Callable<T> task);

    /**
     * 提交可運行任務以執(zhí)行,并返回Future,執(zhí)行結果為傳入的result
     */
    <T> Future<T> submit(Runnable task, T result);

    /**
     * 提交可運行任務以執(zhí)行,并返回Future對象,執(zhí)行結果為null
     */
    Future<?> submit(Runnable task);

    /**
     * 執(zhí)行給定的任務集合,執(zhí)行完畢后,則返回結果。
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;

    /**
     * 執(zhí)行給定的任務集合,執(zhí)行完畢或者超時后,則返回結果,其他任務終止。
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * 執(zhí)行給定的任務,任意一個執(zhí)行成功則返回結果,其他任務終止。
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;

    /**
     * 執(zhí)行給定的任務,任意一個執(zhí)行成功或者超時后,則返回結果,其他任務終止
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}

ScheduledExecutorService

public interface ScheduledExecutorService extends ExecutorService {

    /**
     * 創(chuàng)建并執(zhí)行一個一次性任務,過了延遲時間就會被執(zhí)行
     */
    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

    /**
     * 創(chuàng)建并執(zhí)行一個一次性任務,過了延遲時間就會被執(zhí)行
     */
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);

    /**
     * 創(chuàng)建并執(zhí)行一個周期性任務,過了給定的初始化延遲時間,會第一次被執(zhí)行。執(zhí)行過程中發(fā)生了異常,那么任務停止
     * 一次任務執(zhí)行時長超過了周期時間,下一次任務會等到該次任務執(zhí)行結束后,立刻執(zhí)行,這也是它和scheduleWithTixedDelay的重要區(qū)別
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);

    /**
     * 創(chuàng)建并執(zhí)行一個周期性任務,過了給定的初始化延遲時間,會第一次被執(zhí)行。執(zhí)行過程中發(fā)生了異常,那么任務停止
     * 一次任務執(zhí)行時長超過了周期時間,下一次任務會在該次任務執(zhí)行結束的時間基礎上,計算執(zhí)行延時。
     * 對于超時周期的長時間處理任務的不同處理方式,這是它和scheduleAtFixedRate的重要區(qū)別
     */
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);

}

線程池工具類

在使用過程中,可以自己實例化線程池,也可以用Executors創(chuàng)建線程池的工廠累,常用方法如下:

newFixedThreadPool(int nThreads)

創(chuàng)建一個固定大小、任務隊列容量誤解的線程池。核心線程數=最大線程數。

newCachedThreadPool()

創(chuàng)建的是一個大小無界的緩沖線程池。它的任務隊列是一個同步隊列。任務加入到池中,如果池中有空閑線程,則用空閑線程執(zhí)行,如無則創(chuàng)建新線程執(zhí)行。池中的線程空閑時間超過60秒,將被銷毀釋放。線程數隨任務的多少變化。適用于執(zhí)行耗時較小的異步任務。池的核心線程數=0,最大線程=Integer.MAX_VALUE

newSingleThreadExecutor()

只有一個線程來執(zhí)行無界任務隊列的單一線程池。該線程池確保任務加入的順序一個一個一次執(zhí)行。當唯一的線程因任務異常中止時,將創(chuàng)建一個新的線程來繼續(xù)執(zhí)行后續(xù)的任務。與newFixedThreadPool(1)的區(qū)別在于,單一線程池的池大小在newSingleThreadExecutor方法中硬編碼,不能再改變的。

newScheduledThreadPool(int corePoolSize)

能定時執(zhí)行任務的線程池。該池的核心線程數由參數指定,最大線程數=Integer.MAX_VALUE

任務線程池執(zhí)行過程

如何確認合適的線程數量?

  • 如果是CPU密集型應用,則線程池大小設置為N+1 (N為CPU總核數)
  • 如果是IO密集型應用,則線程池大小設置為2N+1 (N為CPU總核數)
  • 線程等待時間(IO)所占比例越高,需要越多線程。
  • 線程CPU時間所占比例越高,需要越少線程。

一個系統(tǒng)最快的部分是CPU,所以決定一個系統(tǒng)吞吐量上限的是CPU。增強CPU處理能力,可以提高系統(tǒng)吞吐量上限。但根據短板效應,真實的系統(tǒng)吞吐量并不能單純根據CPU來計算。那要提高系統(tǒng)吞吐量,就需要從“系統(tǒng)短板”(比如網絡延遲、IO)著手:

  1. 盡量提高短板操作的并行化比率,比如多線程下載技術;
  2. 增強短板能力,比如用NIO替代IO;

線程池的使用分析

public class ExecutorsUse {
    /**
     * 測試: 提交15 個執(zhí)行時間需要3秒的任務,看線程池的狀況
     *
     * @param threadPoolExecutor 傳入不同的線程池,看不同的結果
     * @throws Exception
     */
    public void testCommon(ThreadPoolExecutor threadPoolExecutor) throws Exception {
        // 測試: 提交15個執(zhí)行時間需要3秒的任務,看超過大小的2個,對應的處理情況
        for (int i = 0; i < 15; i++) {
            int n = i;
            threadPoolExecutor.submit(() -> {
                        try {
                            System.out.println("開始執(zhí)行:" + n);
                            Thread.sleep(3000L);
                            System.err.println("執(zhí)行結束:" + n);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            );
            System.out.println("任務提交成功 :" + i);
        }
        // 查看線程數量,查看隊列等待數量
        Thread.sleep(500L);
        System.out.println("當前線程池線程數量為:" + threadPoolExecutor.getPoolSize());
        System.out.println("當前線程池等待的數量為:" + threadPoolExecutor.getQueue().size());
        // 等待15秒,查看線程數量和隊列數量(理論上,會被超出核心線程數量的線程自動銷毀)
        Thread.sleep(15000L);
        System.out.println("當前線程池線程數量為:" + threadPoolExecutor.getPoolSize());
        System.out.println("當前線程池等待的數量為:" + threadPoolExecutor.getQueue().size());
    }

    /**
     * 1、線程池信息: 核心線程數量5,最大數量10,無界隊列,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest1() throws Exception {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>());
        testCommon(threadPoolExecutor);
        // 預計結果:線程池線程數量為:5,超出數量的任務,其他的進入隊列中等待被執(zhí)行
    }

    /**
     * 2、 線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest2() throws Exception {
        // 創(chuàng)建一個 核心線程數量為5,最大數量為10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
        // 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println("有任務被拒絕執(zhí)行了");
            }
        });
        testCommon(threadPoolExecutor);
        // 預計結果:
        // 1、 5個任務直接分配線程開始執(zhí)行
        // 2、 3個任務進入等待隊列
        // 3、 隊列不夠用,臨時加開5個線程來執(zhí)行任務(5秒沒活干就銷毀)
        // 4、 隊列和線程池都滿了,剩下2個任務,沒資源了,被拒絕執(zhí)行。
        // 5、 任務執(zhí)行,5秒后,如果無任務可執(zhí)行,銷毀臨時創(chuàng)建的5個線程
    }

    /**
     * 3、 線程池信息: 核心線程數量5,最大數量5,無界隊列,超出核心線程數量的線程存活時間:5秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest3() throws Exception {
        // 和Executors.newFixedThreadPool(int nThreads)一樣的
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        testCommon(threadPoolExecutor);
        // 預計結:線程池線程數量為:5,超出數量的任務,其他的進入隊列中等待被執(zhí)行
    }

    /**
     * 4、 線程池信息:
     * 核心線程數量0,最大數量Integer.MAX_VALUE,SynchronousQueue隊列,超出核心線程數量的線程存活時間:60秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest4() throws Exception {

        // SynchronousQueue,實際上它不是一個真正的隊列,因為它不會為隊列中元素維護存儲空間。與其他隊列不同的是,它維護一組線程,這些線程在等待著把元素加入或移出隊列。
        // 在使用SynchronousQueue作為工作隊列的前提下,客戶端代碼向線程池提交任務時,
        // 而線程池中又沒有空閑的線程能夠從SynchronousQueue隊列實例中取一個任務,
        // 那么相應的offer方法調用就會失?。慈蝿諞]有被存入工作隊列)。
        // 此時,ThreadPoolExecutor會新建一個新的工作者線程用于對這個入隊列失敗的任務進行處理(假設此時線程池的大小還未達到其最大線程池大小maximumPoolSize)。

        // 和Executors.newCachedThreadPool()一樣的
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
        testCommon(threadPoolExecutor);
        // 預計結果:
        // 1、 線程池線程數量為:15,超出數量的任務,其他的進入隊列中等待被執(zhí)行
        // 2、 所有任務執(zhí)行結束,60秒后,如果無任務可執(zhí)行,所有線程全部被銷毀,池的大小恢復為0
        Thread.sleep(60000L);
        System.out.println("60秒后,再看線程池中的數量:" + threadPoolExecutor.getPoolSize());
    }

    /**
     * 5、 定時執(zhí)行線程池信息:3秒后執(zhí)行,一次性任務,到點就執(zhí)行 <br/>
     * 核心線程數量5,最大數量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數量的線程存活時間:0秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest5() throws Exception {
        // 和Executors.newScheduledThreadPool()一樣的
        ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
        threadPoolExecutor.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("任務被執(zhí)行,現(xiàn)在時間:" + System.currentTimeMillis());
            }
        }, 3000, TimeUnit.MILLISECONDS);
        System.out.println(
                "定時任務,提交成功,時間是:" + System.currentTimeMillis() + ", 當前線程池中線程數量:" + threadPoolExecutor.getPoolSize());
        // 預計結果:任務在3秒后被執(zhí)行一次
    }

    /**
     * 6、 定時執(zhí)行線程池信息:線程固定數量5 ,<br/>
     * 核心線程數量5,最大數量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數量的線程存活時間:0秒
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest6() throws Exception {
        ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
        // 周期性執(zhí)行某一個任務,線程池提供了兩種調度方式,這里單獨演示一下。測試場景一樣。
        // 測試場景:提交的任務需要3秒才能執(zhí)行完畢。看兩種不同調度方式的區(qū)別
        // 效果1: 提交后,2秒后開始第一次執(zhí)行,之后每間隔1秒,固定執(zhí)行一次(如果發(fā)現(xiàn)上次執(zhí)行還未完畢,則等待完畢,完畢后立刻執(zhí)行)。
        // 也就是說這個代碼中是,3秒鐘執(zhí)行一次(計算方式:每次執(zhí)行三秒,間隔時間1秒,執(zhí)行結束后馬上開始下一次執(zhí)行,無需等待)
        threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任務-1 被執(zhí)行,現(xiàn)在時間:" + System.currentTimeMillis());
            }
        }, 2000, 1000, TimeUnit.MILLISECONDS);

        // 效果2:提交后,2秒后開始第一次執(zhí)行,之后每間隔1秒,固定執(zhí)行一次(如果發(fā)現(xiàn)上次執(zhí)行還未完畢,則等待完畢,等上一次執(zhí)行完畢后再開始計時,等待1秒)。
        // 也就是說這個代碼鐘的效果看到的是:4秒執(zhí)行一次。 (計算方式:每次執(zhí)行3秒,間隔時間1秒,執(zhí)行完以后再等待1秒,所以是 3+1)
        threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任務-2 被執(zhí)行,現(xiàn)在時間:" + System.currentTimeMillis());
            }
        }, 2000, 1000, TimeUnit.MILLISECONDS);
    }

    /**
     * 7、 終止線程:線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest7() throws Exception {
        // 創(chuàng)建一個 核心線程數量為5,最大數量為10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
        // 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println("有任務被拒絕執(zhí)行了");
            }
        });
        // 測試: 提交15個執(zhí)行時間需要3秒的任務,看超過大小的2個,對應的處理情況
        for (int i = 0; i < 15; i++) {
            int n = i;
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("開始執(zhí)行:" + n);
                        Thread.sleep(3000L);
                        System.err.println("執(zhí)行結束:" + n);
                    } catch (InterruptedException e) {
                        System.out.println("異常:" + e.getMessage());
                    }
                }
            });
            System.out.println("任務提交成功 :" + i);
        }
        // 1秒后終止線程池
        Thread.sleep(1000L);
        threadPoolExecutor.shutdown();
        // 再次提交提示失敗
        threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("追加一個任務");
            }
        });
        // 結果分析
        // 1、 10個任務被執(zhí)行,3個任務進入隊列等待,2個任務被拒絕執(zhí)行
        // 2、調用shutdown后,不接收新的任務,等待13任務執(zhí)行結束
        // 3、 追加的任務在線程池關閉后,無法再提交,會被拒絕執(zhí)行
    }

    /**
     * 8、 立刻終止線程:線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
     *
     * @throws Exception
     */
    private void threadPoolExecutorTest8() throws Exception {
        // 創(chuàng)建一個 核心線程數量為5,最大數量為10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
        // 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println("有任務被拒絕執(zhí)行了");
            }
        });
        // 測試: 提交15個執(zhí)行時間需要3秒的任務,看超過大小的2個,對應的處理情況
        for (int i = 0; i < 15; i++) {
            int n = i;
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("開始執(zhí)行:" + n);
                        Thread.sleep(3000L);
                        System.err.println("執(zhí)行結束:" + n);
                    } catch (InterruptedException e) {
                        System.out.println("異常:" + e.getMessage());
                    }
                }
            });
            System.out.println("任務提交成功 :" + i);
        }
        // 1秒后終止線程池
        Thread.sleep(1000L);
        List<Runnable> shutdownNow = threadPoolExecutor.shutdownNow();
        // 再次提交提示失敗
        threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("追加一個任務");
            }
        });
        System.out.println("未結束的任務有:" + shutdownNow.size());

        // 結果分析
        // 1、 10個任務被執(zhí)行,3個任務進入隊列等待,2個任務被拒絕執(zhí)行
        // 2、調用shutdownnow后,隊列中的3個線程不再執(zhí)行,10個線程被終止
        // 3、 追加的任務在線程池關閉后,無法再提交,會被拒絕執(zhí)行
    }

    public static void main(String[] args) throws Exception {
//        new ExecutorsUse().threadPoolExecutorTest1();
//        new ExecutorsUse().threadPoolExecutorTest2();
//          new ExecutorsUse().threadPoolExecutorTest3();
        new ExecutorsUse().threadPoolExecutorTest4();
//        new ExecutorsUse().threadPoolExecutorTest5();
//        new ExecutorsUse().threadPoolExecutorTest6();
//        new ExecutorsUse().threadPoolExecutorTest7();
//        new ExecutorsUse().threadPoolExecutorTest8();
    }
}

合理配置線程池大小

如果想合理設置線程池的線程數量需要考慮兩個問題:

1、需要分析線程池執(zhí)行的任務的特性: CPU 密集型還是 IO 密集型。

2、每個任務執(zhí)行的平均時長大概是多少,這個任務的執(zhí)行時長可能還跟任務處理邏輯是否涉及到網絡傳輸以及底層系統(tǒng)資源依賴有關系。

如果是 CPU 密集型,那線程池的最大線程數可以配置為 cpu 核心數+1;如果是 IO 密集型,線程池設定最佳線程數目 = ((線程池設定的線程等待時間+線程 CPU 時間)/線程 CPU 時間 )* CPU 數目。

線程池的關閉

ThreadPoolExecutor 提供了兩個方法 ,用于線程池的關閉 ,分 別 是 shutdown() 和shutdownNow(),其中:shutdown():不會立即終止線程池,而是要等所有任務緩存隊列中的任務都執(zhí)行完后才終止,但再也不會接受新的任務 shutdownNow():立即終止線程池,并嘗試打斷正在執(zhí)行的任務,并且清空任務緩存隊列,返回尚未執(zhí)行的任務。

總結

到此這篇關于Java中該如何優(yōu)雅的使用線程池的文章就介紹到這了,更多相關Java優(yōu)雅使用線程池內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MybatisPlus中的save方法詳解

    MybatisPlus中的save方法詳解

    save方法是Mybatis-plus框架提供的一個添加記錄的方法,它用于將一個實體對象插入到數據庫表中,這篇文章主要介紹了MybatisPlus中的save方法,需要的朋友可以參考下
    2023-11-11
  • 如何搭建一個完整的Java開發(fā)環(huán)境

    如何搭建一個完整的Java開發(fā)環(huán)境

    這篇文章主要教大家如何搭建一個完整的Java開發(fā)環(huán)境,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java使用Flyway實現(xiàn)數據庫版本控制的技術指南

    Java使用Flyway實現(xiàn)數據庫版本控制的技術指南

    在現(xiàn)代應用開發(fā)中,數據庫結構經常隨著業(yè)務需求不斷演變,使用手動SQL腳本管理數據庫版本,不僅容易出現(xiàn)錯誤,還難以跟蹤和回滾,Flyway是一個強大的數據庫遷移工具,能夠幫助開發(fā)者高效管理和自動化數據庫的版本控制,本文將介紹Flyway的基本功能及其在SpringBoot項目中的實踐
    2025-02-02
  • java實現(xiàn)拼圖游戲

    java實現(xiàn)拼圖游戲

    這篇文章主要為大家詳細介紹了java實現(xiàn)拼圖游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 基于maven中多個子模塊的構建順序

    基于maven中多個子模塊的構建順序

    這篇文章主要介紹了maven中多個子模塊的構建順序,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Mybatis如何構建SQL語句

    Mybatis如何構建SQL語句

    這篇文章主要介紹了Mybatis如何構建SQL語句問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • java socket編程實例代碼講解

    java socket編程實例代碼講解

    這篇文章主要介紹了java socket編程示例講解,大家參考使用吧
    2013-12-12
  • SpringBoot實現(xiàn)JWT token自動續(xù)期的示例代碼

    SpringBoot實現(xiàn)JWT token自動續(xù)期的示例代碼

    本文主要介紹了SpringBoot實現(xiàn)JWT token自動續(xù)期的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • Spring?Security權限管理實現(xiàn)接口動態(tài)權限控制

    Spring?Security權限管理實現(xiàn)接口動態(tài)權限控制

    這篇文章主要為大家介紹了Spring?Security權限管理實現(xiàn)接口動態(tài)權限控制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Java及nginx實現(xiàn)文件權限控制代碼實例

    Java及nginx實現(xiàn)文件權限控制代碼實例

    這篇文章主要介紹了Java及nginx實現(xiàn)文件權限控制代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06

最新評論

正阳县| 兴隆县| 元朗区| 陆丰市| 平安县| 新龙县| 汉阴县| 景东| 天水市| 尉氏县| 汾阳市| 合川市| 成武县| 五峰| 阜新市| 三都| 佛坪县| 开平市| 璧山县| 宾川县| 仙居县| 余干县| 西乡县| 南通市| 利川市| 交城县| 铜梁县| 临高县| 襄汾县| 塘沽区| 昌乐县| 兴仁县| 安陆市| 新宁县| 嘉祥县| 汉川市| 江西省| 万山特区| 峨眉山市| 思南县| 宜阳县|