欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

簡(jiǎn)述Java中進(jìn)程與線程的關(guān)系_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

 更新時(shí)間:2017年05月22日 14:13:37   投稿:mrr  
在 Java 語(yǔ)言中,對(duì)進(jìn)程和線程的封裝,分別提供了 Process 和 Thread 相關(guān)的一些類。本文首先簡(jiǎn)單的介紹如何使用這些類來(lái)創(chuàng)建進(jìn)程和線程

概述

進(jìn)程與線程,本質(zhì)意義上說(shuō), 是操作系統(tǒng)的調(diào)度單位,可以看成是一種操作系統(tǒng) “資源” 。Java 作為與平臺(tái)無(wú)關(guān)的編程語(yǔ)言,必然會(huì)對(duì)底層(操作系統(tǒng))提供的功能進(jìn)行進(jìn)一步的封裝,以平臺(tái)無(wú)關(guān)的編程接口供程序員使用,進(jìn)程與線程作為操作系統(tǒng)核心概念的一部分無(wú)疑亦是如此。在 Java 語(yǔ)言中,對(duì)進(jìn)程和線程的封裝,分別提供了 Process 和 Thread 相關(guān)的一些類。本文首先簡(jiǎn)單的介紹如何使用這些類來(lái)創(chuàng)建進(jìn)程和線程,然后著重介紹這些類是如何和操作系統(tǒng)本地進(jìn)程線程相對(duì)應(yīng)的,給出了 Java 虛擬機(jī)對(duì)于這些封裝類的概要性的實(shí)現(xiàn);同時(shí)由于 Java 的封裝也隱藏了底層的一些概念和可操作性,本文還對(duì) Java 進(jìn)程線程和本地進(jìn)程線程做了一些簡(jiǎn)單的比較,列出了使用 Java 進(jìn)程、線程的一些限制和需要注意的問(wèn)題。

Java 進(jìn)程的建立方法

在 JDK 中,與進(jìn)程有直接關(guān)系的類為 Java.lang.Process,它是一個(gè)抽象類。在 JDK 中也提供了一個(gè)實(shí)現(xiàn)該抽象類的 ProcessImpl 類,如果用戶創(chuàng)建了一個(gè)進(jìn)程,那么肯定會(huì)伴隨著一個(gè)新的 ProcessImpl 實(shí)例。同時(shí)和進(jìn)程創(chuàng)建密切相關(guān)的還有 ProcessBuilder,它是在 JDK1.5 中才開始出現(xiàn)的,相對(duì)于 Process 類來(lái)說(shuō),提供了便捷的配置新建進(jìn)程的環(huán)境,目錄以及是否合并錯(cuò)誤流和輸出流的方式。

Java.lang.Runtime.exec 方法和 Java.lang.ProcessBuilder.start 方法都可以創(chuàng)建一個(gè)本地的進(jìn)程,然后返回代表這個(gè)進(jìn)程的 Java.lang.Process 引用。

Runtime.exec 方法建立一個(gè)本地進(jìn)程

該方法在 JDK1.5 中,可以接受 6 種不同形式的參數(shù)傳入。

 Process exec(String command) 
 Process exec(String [] cmdarray) 
 Process exec(String [] cmdarrag, String [] envp) 
 Process exec(String [] cmdarrag, String [] envp, File dir) 
 Process exec(String cmd, String [] envp) 
 Process exec(String command, String [] envp, File dir)

他們主要的不同在于傳入命令參數(shù)的形式,提供的環(huán)境變量以及定義執(zhí)行目錄。

ProcessBuilder.start 方法來(lái)建立一個(gè)本地的進(jìn)程

如果希望在新創(chuàng)建的進(jìn)程中使用當(dāng)前的目錄和環(huán)境變量,則不需要任何配置,直接將命令行和參數(shù)傳入 ProcessBuilder 中,然后調(diào)用 start 方法,就可以獲得進(jìn)程的引用。

Process p = new ProcessBuilder("command", "param").start();

也可以先配置環(huán)境變量和工作目錄,然后創(chuàng)建進(jìn)程。

 ProcessBuilder pb = new ProcessBuilder("command", "param1", "param2"); 
 Map<String, String> env = pb.environment(); 
 env.put("VAR", "Value"); 
 pb.directory("Dir"); 
 Process p = pb.start();

可以預(yù)先配置 ProcessBuilder 的屬性是通過(guò) ProcessBuilder 創(chuàng)建進(jìn)程的最大優(yōu)點(diǎn)。而且可以在后面的使用中隨著需要去改變代碼中 pb 變量的屬性。如果后續(xù)代碼修改了其屬性,那么會(huì)影響到修改后用 start 方法創(chuàng)建的進(jìn)程,對(duì)修改之前創(chuàng)建的進(jìn)程實(shí)例沒(méi)有影響。

JVM 對(duì)進(jìn)程的實(shí)現(xiàn)

在 JDK 的代碼中,只提供了 ProcessImpl 類來(lái)實(shí)現(xiàn) Process 抽象類。其中引用了 native 的 create, close, waitfor, destory 和 exitValue 方法。在 Java 中,native 方法是依賴于操作系統(tǒng)平臺(tái)的本地方法,它的實(shí)現(xiàn)是用 C/C++ 等類似的底層語(yǔ)言實(shí)現(xiàn)。我們可以在 JVM 的源代碼中找到對(duì)應(yīng)的本地方法,然后對(duì)其進(jìn)行分析。JVM 對(duì)進(jìn)程的實(shí)現(xiàn)相對(duì)比較簡(jiǎn)單,以 Windows 下的 JVM 為例。在 JVM 中,將 Java 中調(diào)用方法時(shí)的傳入的參數(shù)傳遞給操作系統(tǒng)對(duì)應(yīng)的方法來(lái)實(shí)現(xiàn)相應(yīng)的功能。如表 1

表 1. JDK 中 native 方法與 Windows API 的對(duì)應(yīng)關(guān)系

以 create 方法為例,我們看一下它是如何和系統(tǒng) API 進(jìn)行連接的。

在 ProcessImple 類中,存在 native 的 create 方法,其參數(shù)如下:

 private native long create(String cmdstr, String envblock, 
 String dir, boolean redirectErrorStream, FileDescriptor in_fd, 
 FileDescriptor out_fd, FileDescriptor err_fd) throws IOException;

在 JVM 中對(duì)應(yīng)的本地方法如代碼清單 1 所示 。

清單 1

JNIEXPORT jlong JNICALL 
 Java_Java_lang_ProcessImpl_create(JNIEnv *env, jobject process, 
 jstring cmd, 
 jstring envBlock, 
 jstring dir, 
 jboolean redirectErrorStream, 
 jobject in_fd, 
 jobject out_fd, 
 jobject err_fd) 
 { 
   /* 設(shè)置內(nèi)部變量值 */ 
 ……
   /* 建立輸入、輸出以及錯(cuò)誤流管道 */ 
 if (!(CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE) && 
  CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE) && 
  CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE))) { 
  throwIOException(env, "CreatePipe failed"); 
  goto Catch; 
  } 
   /* 進(jìn)行參數(shù)格式的轉(zhuǎn)換 */ 
  pcmd = (LPTSTR) JNU_GetStringPlatformChars(env, cmd, NULL); 
  ……
   /* 調(diào)用系統(tǒng)提供的方法,建立一個(gè) Windows 的進(jìn)程 */ 
  ret = CreateProcess( 
  0,      /* executable name */ 
  pcmd,    /* command line */ 
  0,      /* process security attribute */ 
  0,      /* thread security attribute */ 
  TRUE,    /* inherits system handles */ 
  processFlag, /* selected based on exe type */ 
  penvBlock,  /* environment block */ 
  pdir,    /* change to the new current directory */ 
  &si,   /* (in) startup information */ 
  &pi);   /* (out) process information */ 
 …
   /* 拿到新進(jìn)程的句柄 */ 
  ret = (jlong)pi.hProcess; 
 …
   /* 最后返回該句柄 */ 
  return ret; 
 }

可以看到在創(chuàng)建一個(gè)進(jìn)程的時(shí)候,調(diào)用 Windows 提供的 CreatePipe 方法建立輸入,輸出和錯(cuò)誤管道,同時(shí)將用戶通過(guò) Java 傳入的參數(shù)轉(zhuǎn)換為操作系統(tǒng)可以識(shí)別的 C 語(yǔ)言的格式,然后調(diào)用 Windows 提供的創(chuàng)建系統(tǒng)進(jìn)程的方式,創(chuàng)建一個(gè)進(jìn)程,同時(shí)在 JAVA 虛擬機(jī)中保存了這個(gè)進(jìn)程對(duì)應(yīng)的句柄,然后返回給了 ProcessImpl 類,但是該類將返回句柄進(jìn)行了隱藏。也正是 Java 跨平臺(tái)的特性體現(xiàn),JVM 盡可能的將和操作系統(tǒng)相關(guān)的實(shí)現(xiàn)細(xì)節(jié)進(jìn)行了封裝,并隱藏了起來(lái)。
同樣,在用戶調(diào)用 close、waitfor、destory 以及 exitValue 方法以后, JVM 會(huì)首先取得之前保存的該進(jìn)程在操作系統(tǒng)中的句柄,然后通過(guò)調(diào)用操作系統(tǒng)提供的接口對(duì)該進(jìn)程進(jìn)行操作。通過(guò)這種方式來(lái)實(shí)現(xiàn)對(duì)進(jìn)程的操作。
在其它平臺(tái)下也是用類似的方式實(shí)現(xiàn)的,不同的是調(diào)用的對(duì)應(yīng)平臺(tái)的 API 會(huì)有所不同。

Java 進(jìn)程與操作系統(tǒng)進(jìn)程

通過(guò)上面對(duì) Java 進(jìn)程的分析,其實(shí)它在實(shí)現(xiàn)上就是創(chuàng)建了操作系統(tǒng)的一個(gè)進(jìn)程,也就是每個(gè) JVM 中創(chuàng)建的進(jìn)程都對(duì)應(yīng)了操作系統(tǒng)中的一個(gè)進(jìn)程。但是,Java 為了給用戶更好的更方便的使用,向用戶屏蔽了一些與平臺(tái)相關(guān)的信息,這為用戶需要使用的時(shí)候,帶來(lái)了些許不便。

在使用 C/C++ 創(chuàng)建系統(tǒng)進(jìn)程的時(shí)候,是可以獲得進(jìn)程的 PID 值的,可以直接通過(guò)該 PID 去操作相應(yīng)進(jìn)程。但是在 JAVA 中,用戶只能通過(guò)實(shí)例的引用去進(jìn)行操作,當(dāng)該引用丟失或者無(wú)法取得的時(shí)候,就無(wú)法了解任何該進(jìn)程的信息。

當(dāng)然,Java 進(jìn)程在使用的時(shí)候還有些要注意的事情:

1. Java 提供的輸入輸出的管道容量是十分有限的,如果不及時(shí)讀取會(huì)導(dǎo)致進(jìn)程掛起甚至引起死鎖。

2. 當(dāng)創(chuàng)建進(jìn)程去執(zhí)行 Windows 下的系統(tǒng)命令時(shí),如:dir、copy 等。需要運(yùn)行 windows 的命令解釋器,command.exe/cmd.exe,這依賴于 windows 的版本,這樣才可以運(yùn)行系統(tǒng)的命令。

3. 對(duì)于 Shell 中的管道 ‘ | '命令,各平臺(tái)下的重定向命令符 ‘ > ',都無(wú)法通過(guò)命令參數(shù)直接傳入進(jìn)行實(shí)現(xiàn),而需要在 Java 代碼中做一些處理,如定義新的流來(lái)存儲(chǔ)標(biāo)準(zhǔn)輸出,等等問(wèn)題。

總之,Java 中對(duì)操作系統(tǒng)的進(jìn)程進(jìn)行了封裝,屏蔽了操作系統(tǒng)進(jìn)程相關(guān)的信息。同時(shí),在使用 Java 提供創(chuàng)建進(jìn)程運(yùn)行本地命令的時(shí)候,需要小心使用。

一般而言,使用進(jìn)程是為了執(zhí)行某項(xiàng)任務(wù),而現(xiàn)代操作系統(tǒng)對(duì)于執(zhí)行任務(wù)的計(jì)算資源的配置調(diào)度一般是以線程為對(duì)象(早期的類 Unix 系統(tǒng)因?yàn)椴恢С志€程,所以進(jìn)程也是調(diào)度單位,但那是比較輕量級(jí)的進(jìn)程,在此不做深入討論)。創(chuàng)建一個(gè)進(jìn)程,操作系統(tǒng)實(shí)際上還是會(huì)為此創(chuàng)建相應(yīng)的線程以運(yùn)行一系列指令。特別地,當(dāng)一個(gè)任務(wù)比較龐大復(fù)雜,可能需要?jiǎng)?chuàng)建多個(gè)線程以實(shí)現(xiàn)邏輯上并發(fā)執(zhí)行的時(shí)候,線程的作用更為明顯。因而我們有必要深入了解 Java 中的線程,以避免可能出現(xiàn)的問(wèn)題。本文下面的內(nèi)容即是呈現(xiàn) Java 線程的創(chuàng)建方式以及它與操作系統(tǒng)線程的聯(lián)系與區(qū)別。

Java 創(chuàng)建線程的方法

實(shí)際上,創(chuàng)建線程最重要的是提供線程函數(shù)(回調(diào)函數(shù)),該函數(shù)作為新創(chuàng)建線程的入口函數(shù),實(shí)現(xiàn)自己想要的功能。Java 提供了兩種方法來(lái)創(chuàng)建一個(gè)線程:

1. 繼承 Thread 類

 class MyThread extends Thread{ 
 public void run() { 
  System.out.println("My thread is started."); 
 } 
 }

實(shí)現(xiàn)該繼承類的 run 方法,然后就可以創(chuàng)建這個(gè)子類的對(duì)象,調(diào)用 start 方法即可創(chuàng)建一個(gè)新的線程:

 MyThread myThread = new MyThread(); 
 myThread.start();

2. 實(shí)現(xiàn) Runnable 接口

 class MyRunnable implements Runnable{ 
 public void run() { 
   System.out.println("My runnable is invoked."); 
 } 
 }

實(shí)現(xiàn) Runnable 接口的類的對(duì)象可以作為一個(gè)參數(shù)傳遞到創(chuàng)建的 Thread 對(duì)象中,同樣調(diào)用 Thread#start 方法就可以在一個(gè)新的線程中運(yùn)行 run 方法中的代碼了。 

 Thread myThread = new Thread( new MyRunnable()); 
 myThread.start();

可以看到,不管是用哪種方法,實(shí)際上都是要實(shí)現(xiàn)一個(gè) run 方法的。 該方法本質(zhì)是上一個(gè)回調(diào)方法。由 start 方法新創(chuàng)建的線程會(huì)調(diào)用這個(gè)方法從而執(zhí)行需要的代碼。 從后面可以看到,run 方法并不是真正的線程函數(shù),只是被線程函數(shù)調(diào)用的一個(gè) Java 方法而已,和其他的 Java 方法沒(méi)有什么本質(zhì)的不同。

Java 線程的實(shí)現(xiàn)

從概念上來(lái)說(shuō),一個(gè) Java 線程的創(chuàng)建根本上就對(duì)應(yīng)了一個(gè)本地線程(native thread)的創(chuàng)建,兩者是一一對(duì)應(yīng)的。 問(wèn)題是,本地線程執(zhí)行的應(yīng)該是本地代碼,而 Java 線程提供的線程函數(shù)是 Java 方法,編譯出的是 Java 字節(jié)碼,所以可以想象的是, Java 線程其實(shí)提供了一個(gè)統(tǒng)一的線程函數(shù),該線程函數(shù)通過(guò) Java 虛擬機(jī)調(diào)用 Java 線程方法 , 這是通過(guò) Java 本地方法調(diào)用來(lái)實(shí)現(xiàn)的。

以下是 Thread#start 方法的示例:

 public synchronized void start() { 
   …
   start0(); 
   …
 }

可以看到它實(shí)際上調(diào)用了本地方法 start0, 該方法的聲明如下:

private native void start0();

Thread 類有個(gè) registerNatives 本地方法,該方法主要的作用就是注冊(cè)一些本地方法供 Thread 類使用,如 start0(),stop0() 等等,可以說(shuō),所有操作本地線程的本地方法都是由它注冊(cè)的 . 這個(gè)方法放在一個(gè) static 語(yǔ)句塊中,這就表明,當(dāng)該類被加載到 JVM 中的時(shí)候,它就會(huì)被調(diào)用,進(jìn)而注冊(cè)相應(yīng)的本地方法。

 private static native void registerNatives(); 
 static{ 
    registerNatives(); 
 }

本地方法 registerNatives 是定義在 Thread.c 文件中的。Thread.c 是個(gè)很小的文件,定義了各個(gè)操作系統(tǒng)平臺(tái)都要用到的關(guān)于線程的公用數(shù)據(jù)和操作,如代碼清單 2 所示。

清單 2

JNIEXPORT void JNICALL 
 Java_Java_lang_Thread_registerNatives (JNIEnv *env, jclass cls){ 
  (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); 
 } 
 static JNINativeMethod methods[] = { 
  {"start0", "()V",(void *)&JVM_StartThread}, 
  {"stop0", "(" OBJ ")V", (void *)&JVM_StopThread}, 
 {"isAlive","()Z",(void *)&JVM_IsThreadAlive}, 
 {"suspend0","()V",(void *)&JVM_SuspendThread}, 
 {"resume0","()V",(void *)&JVM_ResumeThread}, 
 {"setPriority0","(I)V",(void *)&JVM_SetThreadPriority}, 
 {"yield", "()V",(void *)&JVM_Yield}, 
 {"sleep","(J)V",(void *)&JVM_Sleep}, 
 {"currentThread","()" THD,(void *)&JVM_CurrentThread}, 
 {"countStackFrames","()I",(void *)&JVM_CountStackFrames}, 
 {"interrupt0","()V",(void *)&JVM_Interrupt}, 
 {"isInterrupted","(Z)Z",(void *)&JVM_IsInterrupted}, 
 {"holdsLock","(" OBJ ")Z",(void *)&JVM_HoldsLock}, 
 {"getThreads","()[" THD,(void *)&JVM_GetAllThreads}, 
 {"dumpThreads","([" THD ")[[" STE, (void *)&JVM_DumpThreads}, 
 };

到此,可以容易的看出 Java 線程調(diào)用 start 的方法,實(shí)際上會(huì)調(diào)用到 JVM_StartThread 方法,那這個(gè)方法又是怎樣的邏輯呢。實(shí)際上,我們需要的是(或者說(shuō) Java 表現(xiàn)行為)該方法最終要調(diào)用 Java 線程的 run 方法,事實(shí)的確如此。 在 jvm.cpp 中,有如下代碼段:

 JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) 
 …
 native_thread = new JavaThread(&thread_entry, sz); 
 …

這里JVM_ENTRY是一個(gè)宏,用來(lái)定義JVM_StartThread 函數(shù),可以看到函數(shù)內(nèi)創(chuàng)建了真正的平臺(tái)相關(guān)的本地線程,其線程函數(shù)是 thread_entry,如清單 3 所示。

清單 3

 static void thread_entry(JavaThread* thread, TRAPS) { 
  HandleMark hm(THREAD); 
 Handle obj(THREAD, thread->threadObj()); 
 JavaValue result(T_VOID); 
 JavaCalls::call_virtual(&result,obj, 
 KlassHandle(THREAD,SystemDictionary::Thread_klass()), 
 vmSymbolHandles::run_method_name(), 
 vmSymbolHandles::void_method_signature(),THREAD); 
 }

可以看到調(diào)用了 vmSymbolHandles::run_method_name 方法,這是在 vmSymbols.hpp 用宏定義的:

class vmSymbolHandles: AllStatic { 
 …
 template(run_method_name,"run") 
 …
 }

至于 run_method_name 是如何聲明定義的,因?yàn)樯婕暗胶芊爆嵉拇a細(xì)節(jié),本文不做贅述。感興趣的讀者可以自行查看 JVM 的源代碼。

圖 1. Java 線程創(chuàng)建調(diào)用關(guān)系圖

 

綜上所述,Java 線程的創(chuàng)建調(diào)用過(guò)程如 圖 1 所示,首先 , Java 線程的 start 方法會(huì)創(chuàng)建一個(gè)本地線程(通過(guò)調(diào)用 JVM_StartThread),該線程的線程函數(shù)是定義在 jvm.cpp 中的 thread_entry,由其再進(jìn)一步調(diào)用 run 方法??梢钥吹?Java 線程的 run 方法和普通方法其實(shí)沒(méi)有本質(zhì)區(qū)別,直接調(diào)用 run 方法不會(huì)報(bào)錯(cuò),但是卻是在當(dāng)前線程執(zhí)行,而不會(huì)創(chuàng)建一個(gè)新的線程。

Java 線程與操作系統(tǒng)線程

從上我們知道,Java 線程是建立在系統(tǒng)本地線程之上的,是另一層封裝,其面向 Java 開發(fā)者提供的接口存在以下的局限性:

線程返回值

Java 沒(méi)有提供方法來(lái)獲取線程的退出返回值。實(shí)際上,線程可以有退出返回值,它一般被操作系統(tǒng)存儲(chǔ)在線程控制結(jié)構(gòu)中 (TCB),調(diào)用者可以通過(guò)檢測(cè)該值來(lái)確定線程是正常退出還是異常終止。

線程的同步

Java 提供方法 Thread#Join()來(lái)等待一個(gè)線程結(jié)束,一般情況這就足夠了,但一種可能的情況是,需要等待在多個(gè)線程上(比如任意一個(gè)線程結(jié)束或者所有線程結(jié)束才會(huì)返回),循環(huán)調(diào)用每個(gè)線程的 Join 方法是不可行的,這可能導(dǎo)致很奇怪的同步問(wèn)題。

線程的 ID

Java 提供的方法 Thread#getID()返回的是一個(gè)簡(jiǎn)單的計(jì)數(shù) ID,其實(shí)和操作系統(tǒng)線程的 ID 沒(méi)有任何關(guān)系。

線程運(yùn)行時(shí)間統(tǒng)計(jì),Java 沒(méi)有提供方法來(lái)獲取線程中某段代碼的運(yùn)行時(shí)間的統(tǒng)計(jì)結(jié)果。雖然可以自行使用計(jì)時(shí)的方法來(lái)實(shí)現(xiàn)(獲取運(yùn)行開始和結(jié)束的時(shí)間,然后相減 ),但由于存在多線程調(diào)度方法的原因,無(wú)法獲取線程實(shí)際使用的 CPU 運(yùn)算時(shí)間,因而必然是不準(zhǔn)確的。

總結(jié)

本文通過(guò)對(duì) Java 進(jìn)程和線程的分析,可以看出 Java 對(duì)這兩種操作系統(tǒng) “資源” 進(jìn)行了封裝,使得開發(fā)人員只需關(guān)注如何使用這兩種 “資源” ,而不必過(guò)多的關(guān)心細(xì)節(jié)。這樣的封裝一方面降低了開發(fā)人員的工作復(fù)雜度,提高了工作效率;另一方面由于封裝屏蔽了操作系統(tǒng)本身的一些特性,因而在使用 Java 進(jìn)程線程時(shí)有了某些限制,這是封裝不可避免的問(wèn)題。語(yǔ)言的演化本就是決定需要什么不需要什么的過(guò)程,相信隨著 Java 的不斷發(fā)展,封裝的功能子集的必然越來(lái)越完善。

相關(guān)文章

  • java中深復(fù)制知識(shí)點(diǎn)詳解

    java中深復(fù)制知識(shí)點(diǎn)詳解

    在本篇文章里小編給大家整理了關(guān)于java中深復(fù)制知識(shí)點(diǎn)詳解內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2020-12-12
  • Java實(shí)現(xiàn)雙端鏈表LinkedList

    Java實(shí)現(xiàn)雙端鏈表LinkedList

    本文主要介紹了Java實(shí)現(xiàn)雙端鏈表LinkedList,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java版的7種單例模式寫法示例

    Java版的7種單例模式寫法示例

    這篇文章主要給大家介紹了關(guān)于Java版的7種單例模式寫法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Hibernate映射解析之關(guān)聯(lián)映射詳解

    Hibernate映射解析之關(guān)聯(lián)映射詳解

    所謂關(guān)聯(lián)映射就是將關(guān)聯(lián)關(guān)系映射到數(shù)據(jù)庫(kù)里,在對(duì)象模型中就是一個(gè)或多個(gè)引用。下面這篇文章詳細(xì)的給大家介紹了Hibernate映射解析之關(guān)聯(lián)映射的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-02-02
  • java?常規(guī)輪詢長(zhǎng)輪詢Long?polling實(shí)現(xiàn)示例詳解

    java?常規(guī)輪詢長(zhǎng)輪詢Long?polling實(shí)現(xiàn)示例詳解

    這篇文章主要為大家介紹了java?常規(guī)輪詢長(zhǎng)輪詢Long?polling實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 使用Maven Helper解決Maven插件沖突的方法

    使用Maven Helper解決Maven插件沖突的方法

    這篇文章主要介紹了使用Maven Helper解決Maven插件沖突的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • jstl標(biāo)簽基礎(chǔ)開發(fā)步驟(詳解)

    jstl標(biāo)簽基礎(chǔ)開發(fā)步驟(詳解)

    下面小編就為大家?guī)?lái)一篇jstl標(biāo)簽基礎(chǔ)開發(fā)步驟(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • 簡(jiǎn)單了解JavaCAS的相關(guān)知識(shí)原理

    簡(jiǎn)單了解JavaCAS的相關(guān)知識(shí)原理

    這篇文章主要介紹了簡(jiǎn)單了解JavaCAS的相關(guān)知識(shí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Spring AOP的幾種實(shí)現(xiàn)方式總結(jié)

    Spring AOP的幾種實(shí)現(xiàn)方式總結(jié)

    本篇文章主要介紹了Spring AOP的幾種實(shí)現(xiàn)方式總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • Springboot解決跨域問(wèn)題方案總結(jié)(包括Nginx,Gateway網(wǎng)關(guān)等)

    Springboot解決跨域問(wèn)題方案總結(jié)(包括Nginx,Gateway網(wǎng)關(guān)等)

    跨域問(wèn)題是瀏覽器為了保護(hù)用戶的信息安全,實(shí)施了同源策略(Same-Origin?Policy),即只允許頁(yè)面請(qǐng)求同源(相同協(xié)議、域名和端口)的資源,本文給大家總結(jié)了Springboot解決跨域問(wèn)題方案包括Nginx,Gateway網(wǎng)關(guān)等),需要的朋友可以參考下
    2024-03-03

最新評(píng)論