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

Java并發(fā)編程之創(chuàng)建線程

 更新時(shí)間:2016年02月22日 16:18:57   作者:海 子  
這篇文章主要介紹了Java并發(fā)編程中創(chuàng)建線程的方法,Java中如何創(chuàng)建線程,讓線程去執(zhí)行一個(gè)子任務(wù),感興趣的小伙伴們可以參考一下

先講述一下Java中的應(yīng)用程序和進(jìn)程相關(guān)的概念知識(shí),然后再闡述如何創(chuàng)建線程以及如何創(chuàng)建進(jìn)程。下面是本文的目錄大綱:

一.Java中關(guān)于應(yīng)用程序和進(jìn)程相關(guān)的概念

二.Java中如何創(chuàng)建線程

三.Java中如何創(chuàng)建進(jìn)程

一.Java中關(guān)于應(yīng)用程序和進(jìn)程相關(guān)的概念

在Java中,一個(gè)應(yīng)用程序?qū)?yīng)著一個(gè)JVM實(shí)例(也有地方稱為JVM進(jìn)程),一般來說名字默認(rèn)為java.exe或者javaw.exe(windows下可以通過任務(wù)管理器查看)。Java采用的是單線程編程模型,即在我們自己的程序中如果沒有主動(dòng)創(chuàng)建線程的話,只會(huì)創(chuàng)建一個(gè)線程,通常稱為主線程。但是要注意,雖然只有一個(gè)線程來執(zhí)行任務(wù),不代表JVM中只有一個(gè)線程,JVM實(shí)例在創(chuàng)建的時(shí)候,同時(shí)會(huì)創(chuàng)建很多其他的線程(比如垃圾收集器線程)。

由于Java采用的是單線程編程模型,因此在進(jìn)行UI編程時(shí)要注意將耗時(shí)的操作放在子線程中進(jìn)行,以避免阻塞主線程(在UI編程時(shí),主線程即UI線程,用來處理用戶的交互事件)。

二.Java中如何創(chuàng)建線程

在java中如果要?jiǎng)?chuàng)建線程的話,一般有兩種方式:1)繼承Thread類;2)實(shí)現(xiàn)Runnable接口。

1.繼承Thread類

繼承Thread類的話,必須重寫run方法,在run方法中定義需要執(zhí)行的任務(wù)。

class MyThread extends Thread{
 private static int num = 0;
 
 public MyThread(){
 num++;
 }
 
 @Override
 public void run() {
 System.out.println("主動(dòng)創(chuàng)建的第"+num+"個(gè)線程");
 }
}

創(chuàng)建好了自己的線程類之后,就可以創(chuàng)建線程對(duì)象了,然后通過start()方法去啟動(dòng)線程。注意,不是調(diào)用run()方法啟動(dòng)線程,run方法中只是定義需要執(zhí)行的任務(wù),如果調(diào)用run方法,即相當(dāng)于在主線程中執(zhí)行run方法,跟普通的方法調(diào)用沒有任何區(qū)別,此時(shí)并不會(huì)創(chuàng)建一個(gè)新的線程來執(zhí)行定義的任務(wù)。

public class Test {
 public static void main(String[] args) {
 MyThread thread = new MyThread();
 thread.start();
 }
}
 
class MyThread extends Thread{
 private static int num = 0;
 
 public MyThread(){
 num++;
 }
 
 @Override
 public void run() {
 System.out.println("主動(dòng)創(chuàng)建的第"+num+"個(gè)線程");
 }
}

在上面代碼中,通過調(diào)用start()方法,就會(huì)創(chuàng)建一個(gè)新的線程了。為了分清start()方法調(diào)用和run()方法調(diào)用的區(qū)別,請(qǐng)看下面一個(gè)例子:

public class Test {
 public static void main(String[] args) {
 System.out.println("主線程ID:"+Thread.currentThread().getId());
 MyThread thread1 = new MyThread("thread1");
 thread1.start();
 MyThread thread2 = new MyThread("thread2");
 thread2.run();
 }
}
 
class MyThread extends Thread{
 private String name;
 
 public MyThread(String name){
 this.name = name;
 }
 
 @Override
 public void run() {
 System.out.println("name:"+name+" 子線程ID:"+Thread.currentThread().getId());
 }
}

運(yùn)行結(jié)果:

從輸出結(jié)果可以得出以下結(jié)論:

1)thread1和thread2的線程ID不同,thread2和主線程ID相同,說明通過run方法調(diào)用并不會(huì)創(chuàng)建新的線程,而是在主線程中直接運(yùn)行run方法,跟普通的方法調(diào)用沒有任何區(qū)別;

2)雖然thread1的start方法調(diào)用在thread2的run方法前面調(diào)用,但是先輸出的是thread2的run方法調(diào)用的相關(guān)信息,說明新線程創(chuàng)建的過程不會(huì)阻塞主線程的后續(xù)執(zhí)行。

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

在Java中創(chuàng)建線程除了繼承Thread類之外,還可以通過實(shí)現(xiàn)Runnable接口來實(shí)現(xiàn)類似的功能。實(shí)現(xiàn)Runnable接口必須重寫其run方法。

下面是一個(gè)例子:

public class Test {
 public static void main(String[] args) {
 System.out.println("主線程ID:"+Thread.currentThread().getId());
 MyRunnable runnable = new MyRunnable();
 Thread thread = new Thread(runnable);
 thread.start();
 }
}
 
class MyRunnable implements Runnable{
 
 public MyRunnable() {
 
 }
 
 @Override
 public void run() {
 System.out.println("子線程ID:"+Thread.currentThread().getId());
 }
}

Runnable的中文意思是“任務(wù)”,顧名思義,通過實(shí)現(xiàn)Runnable接口,我們定義了一個(gè)子任務(wù),然后將子任務(wù)交由Thread去執(zhí)行。注意,這種方式必須將Runnable作為Thread類的參數(shù),然后通過Thread的start方法來創(chuàng)建一個(gè)新線程來執(zhí)行該子任務(wù)。如果調(diào)用Runnable的run方法的話,是不會(huì)創(chuàng)建新線程的,這根普通的方法調(diào)用沒有任何區(qū)別。

事實(shí)上,查看Thread類的實(shí)現(xiàn)源代碼會(huì)發(fā)現(xiàn)Thread類是實(shí)現(xiàn)了Runnable接口的。

在Java中,這2種方式都可以用來創(chuàng)建線程去執(zhí)行子任務(wù),具體選擇哪一種方式要看自己的需求。直接繼承Thread類的話,可能比實(shí)現(xiàn)Runnable接口看起來更加簡(jiǎn)潔,但是由于Java只允許單繼承,所以如果自定義類需要繼承其他類,則只能選擇實(shí)現(xiàn)Runnable接口。

三.Java中如何創(chuàng)建進(jìn)程

在Java中,可以通過兩種方式來創(chuàng)建進(jìn)程,總共涉及到5個(gè)主要的類。

第一種方式是通過Runtime.exec()方法來創(chuàng)建一個(gè)進(jìn)程,第二種方法是通過ProcessBuilder的start方法來創(chuàng)建進(jìn)程。下面就來講一講這2種方式的區(qū)別和聯(lián)系。

首先要講的是Process類,Process類是一個(gè)抽象類,在它里面主要有幾個(gè)抽象的方法,這個(gè)可以通過查看Process類的源代碼得知:

位于java.lang.Process路徑下:

public class Test {
 public static void main(String[] args) {
 System.out.println("主線程ID:"+Thread.currentThread().getId());
 MyRunnable runnable = new MyRunnable();
 Thread thread = new Thread(runnable);
 thread.start();
 }
}
 
class MyRunnable implements Runnable{
 
 public MyRunnable() {
 
 }
 
 @Override
 public void run() {
 System.out.println("子線程ID:"+Thread.currentThread().getId());
 }
}

1)通過ProcessBuilder創(chuàng)建進(jìn)程

ProcessBuilder是一個(gè)final類,它有兩個(gè)構(gòu)造器:

public final class ProcessBuilder
{
 private List<String> command;
 private File directory;
 private Map<String,String> environment;
 private boolean redirectErrorStream;
 
 public ProcessBuilder(List<String> command) {
 if (command == null)
 throw new NullPointerException();
 this.command = command;
 }
 
 public ProcessBuilder(String... command) {
 this.command = new ArrayList<String>(command.length);
 for (String arg : command)
 this.command.add(arg);
 }
....
}

構(gòu)造器中傳遞的是需要?jiǎng)?chuàng)建的進(jìn)程的命令參數(shù),第一個(gè)構(gòu)造器是將命令參數(shù)放進(jìn)List當(dāng)中傳進(jìn)去,第二構(gòu)造器是以不定長(zhǎng)字符串的形式傳進(jìn)去。

那么我們接著往下看,前面提到是通過ProcessBuilder的start方法來創(chuàng)建一個(gè)新進(jìn)程的,我們看一下start方法中具體做了哪些事情。下面是start方法的具體實(shí)現(xiàn)源代碼:

public Process start() throws IOException {
// Must convert to array first -- a malicious user-supplied
// list might try to circumvent the security check.
String[] cmdarray = command.toArray(new String[command.size()]);
for (String arg : cmdarray)
 if (arg == null)
 throw new NullPointerException();
// Throws IndexOutOfBoundsException if command is empty
String prog = cmdarray[0];
 
SecurityManager security = System.getSecurityManager();
if (security != null)
 security.checkExec(prog);
 
String dir = directory == null ? null : directory.toString();
 
try {
 return ProcessImpl.start(cmdarray,
 environment,
 dir,
 redirectErrorStream);
} catch (IOException e) {
 // It's much easier for us to create a high-quality error
 // message than the low-level C code which found the problem.
 throw new IOException(
 "Cannot run program \"" + prog + "\""
 + (dir == null ? "" : " (in directory \"" + dir + "\")")
 + ": " + e.getMessage(),
 e);
}
}

該方法返回一個(gè)Process對(duì)象,該方法的前面部分相當(dāng)于是根據(jù)命令參數(shù)以及設(shè)置的工作目錄進(jìn)行一些參數(shù)設(shè)定,最重要的是try語句塊里面的一句:

return ProcessImpl.start(cmdarray,
 environment,
 dir,
 redirectErrorStream);

說明真正創(chuàng)建進(jìn)程的是這一句,注意調(diào)用的是ProcessImpl類的start方法,此處可以知道start必然是一個(gè)靜態(tài)方法。那么ProcessImpl又是什么類呢?該類同樣位于java.lang.ProcessImpl路徑下,看一下該類的具體實(shí)現(xiàn):

ProcessImpl也是一個(gè)final類,它繼承了Process類:

final class ProcessImpl extends Process {
 
 // System-dependent portion of ProcessBuilder.start()
 static Process start(String cmdarray[],
 java.util.Map<String,String> environment,
 String dir,
 boolean redirectErrorStream)
 throws IOException
 {
 String envblock = ProcessEnvironment.toEnvironmentBlock(environment);
 return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream);
 }
 ....
}

這是ProcessImpl類的start方法的具體實(shí)現(xiàn),而事實(shí)上start方法中是通過這句來創(chuàng)建一個(gè)ProcessImpl對(duì)象的:

return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream);
而在ProcessImpl中對(duì)Process類中的幾個(gè)抽象方法進(jìn)行了具體實(shí)現(xiàn)。

說明事實(shí)上通過ProcessBuilder的start方法創(chuàng)建的是一個(gè)ProcessImpl對(duì)象。

下面看一下具體使用ProcessBuilder創(chuàng)建進(jìn)程的例子,比如我要通過ProcessBuilder來啟動(dòng)一個(gè)進(jìn)程打開cmd,并獲取ip地址信息,那么可以這么寫:

public class Test {
 public static void main(String[] args) throws IOException {
 ProcessBuilder pb = new ProcessBuilder("cmd","/c","ipconfig/all");
 Process process = pb.start();
 Scanner scanner = new Scanner(process.getInputStream());
 
 while(scanner.hasNextLine()){
 System.out.println(scanner.nextLine());
 }
 scanner.close();
 }
}

第一步是最關(guān)鍵的,就是將命令字符串傳給ProcessBuilder的構(gòu)造器,一般來說,是把字符串中的每個(gè)獨(dú)立的命令作為一個(gè)單獨(dú)的參數(shù),不過也可以按照順序放入List中傳進(jìn)去。

至于其他很多具體的用法不在此進(jìn)行贅述,比如通過ProcessBuilder的environment方法和directory(File directory)設(shè)置進(jìn)程的環(huán)境變量以及工作目錄等,感興趣的朋友可以查看相關(guān)API文檔。

2)通過Runtime的exec方法來創(chuàng)建進(jìn)程

首先還是來看一下Runtime類和exec方法的具體實(shí)現(xiàn),Runtime,顧名思義,即運(yùn)行時(shí),表示當(dāng)前進(jìn)程所在的虛擬機(jī)實(shí)例。

由于任何進(jìn)程只會(huì)運(yùn)行于一個(gè)虛擬機(jī)實(shí)例當(dāng)中,所以在Runtime中采用了單例模式,即只會(huì)產(chǎn)生一個(gè)虛擬機(jī)實(shí)例:

public class Runtime {
 private static Runtime currentRuntime = new Runtime();
 
 /**
 * Returns the runtime object associated with the current Java application.
 * Most of the methods of class <code>Runtime</code> are instance
 * methods and must be invoked with respect to the current runtime object.
 *
 * @return the <code>Runtime</code> object associated with the current
 * Java application.
 */
 public static Runtime getRuntime() {
 return currentRuntime;
 }
 
 /** Don't let anyone else instantiate this class */
 private Runtime() {}
 ...
 }

從這里可以看出,由于Runtime類的構(gòu)造器是private的,所以只有通過getRuntime去獲取Runtime的實(shí)例。接下來著重看一下exec方法 實(shí)現(xiàn),在Runtime中有多個(gè)exec的不同重載實(shí)現(xiàn),但真正最后執(zhí)行的是這個(gè)版本的exec方法:

public Process exec(String[] cmdarray, String[] envp, File dir)
 throws IOException {
 return new ProcessBuilder(cmdarray)
 .environment(envp)
 .directory(dir)
 .start();
 }

可以發(fā)現(xiàn),事實(shí)上通過Runtime類的exec創(chuàng)建進(jìn)程的話,最終還是通過ProcessBuilder類的start方法來創(chuàng)建的。

下面看一個(gè)例子,看一下通過Runtime的exec如何創(chuàng)建進(jìn)程,還是前面的例子,調(diào)用cmd,獲取ip地址信息:

public class Test {
 public static void main(String[] args) throws IOException {
 String cmd = "cmd "+"/c "+"ipconfig/all";
 Process process = Runtime.getRuntime().exec(cmd);
 Scanner scanner = new Scanner(process.getInputStream());
 
 while(scanner.hasNextLine()){
 System.out.println(scanner.nextLine());
 }
 scanner.close();
 }
}

要注意的是,exec方法不支持不定長(zhǎng)參數(shù)(ProcessBuilder是支持不定長(zhǎng)參數(shù)的),所以必須先把命令參數(shù)拼接好再傳進(jìn)去。

關(guān)于在Java中如何創(chuàng)建線程和進(jìn)程的話,暫時(shí)就講這么多了,感興趣的朋友可以參考相關(guān)資料。

相關(guān)文章

  • java按字節(jié)截取帶有漢字的字符串的解法(推薦)

    java按字節(jié)截取帶有漢字的字符串的解法(推薦)

    下面小編就為大家?guī)硪黄猨ava按字節(jié)截取帶有漢字的字符串的解法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-09-09
  • JAVA中的函數(shù)接口示例詳解

    JAVA中的函數(shù)接口示例詳解

    創(chuàng)建一個(gè)自定義的Sayable接口,這是一個(gè)使用@FunctionalInterface注解的函數(shù)式接口,這篇文章主要介紹了JAVA中的函數(shù)接口,你都用過嗎,需要的朋友可以參考下
    2023-11-11
  • Java8中Function接口的使用方法詳解

    Java8中Function接口的使用方法詳解

    在 Java 8 中,Function 接口是 java.util.function 包中的一個(gè)函數(shù)式接口,函數(shù)式接口是僅包含一個(gè)抽象方法的接口,適用于 Lambda 表達(dá)式或方法引用,本文給大家介紹了Java8的Function接口的使用方法,需要的朋友可以參考下
    2024-09-09
  • 詳解如何在Spring中為@Value注解設(shè)置默認(rèn)值

    詳解如何在Spring中為@Value注解設(shè)置默認(rèn)值

    在Spring開發(fā)中,我們經(jīng)常會(huì)遇到需要從配置文件中讀取屬性的情況,@Value注解是Spring提供的一種便捷方式,能夠讓我們輕松地將配置文件中的屬性注入到Spring Bean中,
    2024-10-10
  • spring MVC + bootstrap實(shí)現(xiàn)文件上傳示例(帶進(jìn)度條)

    spring MVC + bootstrap實(shí)現(xiàn)文件上傳示例(帶進(jìn)度條)

    本篇文章主要介紹了spring MVC + bootstrap實(shí)現(xiàn)文件上傳示例(帶進(jìn)度條),非常具有使用價(jià)值,有需要的朋友可以了解一下。
    2017-03-03
  • JAVA如何判斷上傳文件后綴名是否符合規(guī)范MultipartFile

    JAVA如何判斷上傳文件后綴名是否符合規(guī)范MultipartFile

    這篇文章主要介紹了JAVA判斷上傳文件后綴名是否符合規(guī)范MultipartFile,文中通過實(shí)例代碼介紹了java實(shí)現(xiàn)對(duì)上傳文件做安全性檢查,需要的朋友可以參考下
    2023-11-11
  • 支持SpEL表達(dá)式的自定義日志注解@SysLog介紹

    支持SpEL表達(dá)式的自定義日志注解@SysLog介紹

    這篇文章主要介紹了支持SpEL表達(dá)式的自定義日志注解@SysLog,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • SpringBoot下載文件的實(shí)現(xiàn)及速度對(duì)比

    SpringBoot下載文件的實(shí)現(xiàn)及速度對(duì)比

    這篇文章主要介紹了SpringBoot下載文件的實(shí)現(xiàn)及速度對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java 中 String,StringBuffer 和 StringBuilder 的區(qū)別及用法

    Java 中 String,StringBuffer 和 StringBuilder 的區(qū)別及用法

    這篇文章主要介紹了Java 中 String,StringBuffer 和 StringBuilder 的區(qū)別及用法的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 在eclipse中使用SVN的方法(圖文)

    在eclipse中使用SVN的方法(圖文)

    這篇文章主要介紹了在eclipse中使用SVN的方法(圖文),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08

最新評(píng)論

淮北市| 阿瓦提县| 东安县| 扶余县| 河津市| 茌平县| 拉孜县| 彩票| 五指山市| 班玛县| 隆子县| 岗巴县| 敦煌市| 鲜城| 高碑店市| 额尔古纳市| 桦川县| 孙吴县| 鹤山市| 公安县| 四平市| 微山县| 洪泽县| 青铜峡市| 旬阳县| 施秉县| 准格尔旗| 马龙县| 临江市| 屏山县| 西丰县| 宣恩县| 陇南市| 泽普县| 门头沟区| 武汉市| 万荣县| 焉耆| 广德县| 石河子市| 肥东县|