1. 程式人生 > >java多執行緒的6種實現方式詳解、執行緒池、定時器

java多執行緒的6種實現方式詳解、執行緒池、定時器

多執行緒的形式上實現方式主要有兩種,一種是繼承Thread類,一種是實現Runnable介面。本質上實現方式都是來實現執行緒任務,然後啟動執行緒執行執行緒任務(這裡的執行緒任務實際上就是run方法)。這裡所說的6種,實際上都是在以上兩種的基礎上的一些變形。

繼承Thread類

萬物皆物件,那麼執行緒也是物件,物件就應該能夠抽取其公共特性封裝成為類,使用類可以例項化多個物件,那麼實現執行緒的第一種方式就是繼承Thread類的方式。繼承Thread類是最簡單的一種實現執行緒的方式,通過jdk給我們提供的Thread類,重寫Thread類的run方法即可,那麼當執行緒啟動的時候,就會執行run方法體的內容。程式碼如下:

package com.hy.thread.t1;

/**
 * 繼承Thread類的方式實現多執行緒演示
 * 
 * @author 007
 *
 */
public classThreadDemoextendsThread {

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
            try {
                Thread.sleep(1000
); // 休息1000ms } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { ThreadDemo td = new ThreadDemo(); td.start(); // 啟動執行緒 while (true) { System.out.println(Thread.currentThread().getName() + " is running ... "
); // 列印當前執行緒的名字 try { Thread.sleep(1000); // 休息1000ms } catch (InterruptedException e) { e.printStackTrace(); } } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

執行結果如下

main is running ... 
Thread-0 is running ... 
main is running ... 
Thread-0 is running ... 
Thread-0 is running ... 
main is running ... 
Thread-0 is running ... 
main is running ... 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

這裡要注意,在啟動執行緒的時候,我們並不是呼叫執行緒類的run方法,而是呼叫了執行緒類的start方法。那麼我們能不能呼叫run方法呢?答案是肯定的,因為run方法是一個public宣告的方法,因此我們是可以呼叫的,但是如果我們呼叫了run方法,那麼這個方法將會作為一個普通的方法被呼叫,並不會開啟執行緒。這裡實際上是採用了設計模式中的模板方法模式,Thread類作為模板,而run方法是在變化的因此放到子類。

建立多個執行緒

上面的例子中除了我們建立的一個執行緒以外其實還有一個主執行緒也在執行。除了這兩個執行緒以外還有沒有其他的執行緒在執行了呢,其實是有的,比如我們看不到的垃圾回收執行緒,也在默默的執行。這裡我們並不去考慮有多少個執行緒在執行,上面我們自己建立了一個執行緒,那麼能不能多建立幾個一起執行呢,答案是肯定的。一個Thread類就是一個執行緒物件,那麼多建立幾個Thread類,並呼叫其start方法就可以啟動多個執行緒了。程式碼如下

package com.hy.thread.t1;

public classMultiThreadDemoextendsThread {

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {

        // 建立四個執行緒物件,代表四個執行緒
        MultiThreadDemo td1 = new MultiThreadDemo();
        MultiThreadDemo td2 = new MultiThreadDemo();
        MultiThreadDemo td3 = new MultiThreadDemo();
        MultiThreadDemo td4 = new MultiThreadDemo();

        td1.start(); // 啟動執行緒
        td2.start(); // 啟動執行緒
        td3.start(); // 啟動執行緒
        td4.start(); // 啟動執行緒

        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

執行結果如下

main is running ... 
Thread-2 is running ... 
Thread-1 is running ... 
Thread-3 is running ... 
Thread-0 is running ... 
Thread-3 is running ... 
Thread-2 is running ... 
main is running ... 
Thread-1 is running ... 
Thread-0 is running ... 
Thread-1 is running ... 
main is running ... 
Thread-2 is running ... 
Thread-0 is running ... 
Thread-3 is running ... 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我們發現這裡有個問題,多個執行緒的名字都是系統定義好的,就是Thread-開頭,後面跟數字,如果我們每個執行緒處理不同的任務,那麼我們能不能給執行緒起上不同的名字,方便我們排查問題呢?答案是可以的。只要在建立執行緒例項的時候,在構造方法中傳入指定的執行緒名稱即可。如下

package com.hy.thread.t1;

public classMultiThreadDemoextendsThread {

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 指定執行緒名稱的構造方法
     * 
     * @param name
     */
    public MultiThreadDemo(String name) {
        super(name);
    }

    public static void main(String[] args) {

        // 建立四個執行緒物件,代表四個執行緒
        MultiThreadDemo td1 = new MultiThreadDemo("t1"); // 指定執行緒的名字
        MultiThreadDemo td2 = new MultiThreadDemo("t2");
        MultiThreadDemo td3 = new MultiThreadDemo("t3");
        MultiThreadDemo td4 = new MultiThreadDemo("t4");

        td1.start(); // 啟動執行緒
        td2.start(); // 啟動執行緒
        td3.start(); // 啟動執行緒
        td4.start(); // 啟動執行緒

        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

執行的結果如下:

main is running ... 
t1 is running ... 
t2 is running ... 
t3 is running ... 
t4 is running ... 
main is running ... 
t1 is running ... 
t2 is running ... 
t4 is running ... 
t3 is running ... 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

實現Runnable介面

實現Runnable介面也是一種常見的建立執行緒的方式。使用介面的方式可以讓我們的程式降低耦合度。Runnable介面中僅僅定義了一個方法,就是run。我們來看一下Runnable介面的程式碼。

package java.lang;

@FunctionalInterface
public interfaceRunnable {
    public abstract void run();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其實Runnable就是一個執行緒任務,執行緒任務和執行緒的控制分離,這也就是上面所說的解耦。我們要實現一個執行緒,可以藉助Thread類,Thread類要執行的任務就可以由實現了Runnable介面的類來處理。 這就是Runnable的精髓之所在!

使用Runnable實現上面的例子步驟如下:

  • 定義一個類實現Runnable介面,作為執行緒任務類
  • 重寫run方法,並實現方法體,方法體的程式碼就是執行緒所執行的程式碼
  • 定義一個可以執行的類,並在main方法中建立執行緒任務類
  • 建立Thread類,並將執行緒任務類做為Thread類的構造方法傳入
  • 啟動執行緒

執行緒任務類程式碼如下

package com.hy.thread.t2;

public classThreadTargetimplementsRunnable {

    @Override
    public void run() {
        while(true) {
            System.out.println(Thread.currentThread().getName() + " is running .. ");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

可執行類程式碼如下

package com.hy.thread.t2;

public class Main {

    public static void main(String[] args) {

        ThreadTarget tt = new ThreadTarget(); // 例項化執行緒任務類
        Thread t = new Thread(tt); // 建立執行緒物件,並將執行緒任務類作為構造方法引數傳入
        t.start(); // 啟動執行緒

        // 主執行緒的任務,為了演示多個執行緒一起執行
        while(true) {
            System.out.println(Thread.currentThread().getName() + " is running .. ");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

執行緒任務和執行緒的控制分離,那麼一個執行緒任務可以提交給多個執行緒來執行。這是很有用的,比如車站的售票視窗,每個視窗可以看做是一個執行緒,他們每個視窗做的事情都是一樣的,也就是售票。這樣我們程式在模擬現實的時候就可以定義一個售票任務,讓多個視窗同時執行這一個任務。那麼如果要改動任務執行計劃,只要修改執行緒任務類,所有的執行緒就都會按照修改後的來執行。相比較繼承Thread類的方式來建立執行緒的方式,實現Runnable介面是更為常用的。

使用內部類的方式

這並不是一種新的實現執行緒的方式,只是另外的一種寫法。比如有些情況我們的執行緒就想執行一次,以後就用不到了。那麼像上面兩種方式都還要再定義一個類,顯得比較麻煩,我們就可以通過匿名內部類的方式來實現。使用內部類實現依然有兩種,分別是繼承Thread類和實現Runnable介面。程式碼如下:

package com.hy.thread.t3;

public classDemoThread {

    public static void main(String[] args) {

        // 基於子類的實現
        new Thread() {
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
                    try {
                        Thread.sleep(1000); // 休息1000ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
        }.start();

        // 基於介面的實現
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
                    try {
                        Thread.sleep(1000); // 休息1000ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        // 主執行緒的方法
        while (true) {
            System.out.println(Thread.currentThread().getName() + " is running ... "); // 列印當前執行緒的名字
            try {
                Thread.sleep(1000); // 休息1000ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

可以想象一下,我能不能既基於介面,又基於子類呢?像下面的程式碼會執行出什麼樣子呢?

package com.hy.thread.t3;

public class DemoThred2 {

    public static void main(String[] args) {


        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    System.out.println("runnable is running ... "); // 列印當前執行緒的名字
                    try {
                        Thread.sleep(1000); // 休息1000ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }) {
            public void run() {
                while (true) {
                    System.out.println("sub is running ... "); // 列印當前執行緒的名字
                    try {
                        Thread.sleep(1000); // 休息1000ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
        }.start();


    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

執行結果如下:

sub is running ... 
sub is running ... 
sub is running ... 
  • 1
  • 2
  • 3
  • 4

我們可以看到,其實是基於子類的執行了,為什麼呢,其實很簡單,我們先來看一下為什麼不基於子類的時候Runnable的run方法可以執行。這個要從Thread的原始碼看起,下面是我擷取的程式碼片段。

    public Thread(Runnable target)
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }

    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");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        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);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

其實上面的眾多程式碼就是為了表現 this.target = target 那麼target是什麼呢,是Thread類的成員變數。那麼在什麼地方用到了target呢?下面是run方法的內容。

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我們可以看到,如果通過上面的構造方法傳入target,那麼就會執行target中的run方法。可能有朋友就會問了,我們同時繼承Thread類和實現Runnable介面,target不為空,那麼為何不執行target的run呢。不要忘記了,我們在子類中已經重寫了Thread類的run方法,因此run方法已經不在是我們看到的這樣了。那當然也就不回執行target的run方法。

定時器

定時器可以說是一種基於執行緒的一個工具類。可以定時的來執行某個任務。比如要在凌晨的時候彙總一些資料,比如要每隔10分鐘抓取一次某個網站上的資料等等,總之計時器無處不在。我們一般將需要定時完成的任務稱之為計劃任務,這在很多的系統中是非常常見的,比如linux的計劃任務,比如Windows下的任務計劃等等。我們自己的系統中也需要很多定時執行的也都需要計劃任務。最簡單的計劃任務就可以通過jdk給我提供的API來實現,當然也有很多的計劃任務的框架,比如spring的schedule以及著名的quartz。我們這裡不去討論其他的計劃任務框架,我們就來看一下jdk所給我們提供的API來實現定時任務。

  • 例1:在2017年10月11日晚上10點執行任務。
package com.roocon.thread.t3;

import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 定時器舉例
 * 
 */
public classTimerDemo {

    private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    public static void main(String[] args) throws Exception {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("定時任務執行了....");
            }
        }, format.parse("2017-10-11 22:00:00"));
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 例2: 每隔5s執行一次
package com.roocon.thread.t3;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public classTimerDemo2 {

    public static void main(String[] args) {
        Timer timer = new Timer();

        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println("Hello");
            }
        }, new Date(), 5000);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

關於Spring的定時任務,可以通過spring的教程來學習。

帶返回值的執行緒實現方式

我們發現上面提到的不管是繼承Thread類還是實現Runnable介面,發現有兩個問題,第一個是無法丟擲更多的異常,第二個是執行緒執行完畢之後並無法獲得執行緒的返回值。那麼下面的這種實現方式就可以完成我們的需求。這種方式的實現就是我們後面要詳細介紹的Future模式,只是在jdk5的時候,官方給我們提供了可用的API,我們可以直接使用。但是使用這種方式建立執行緒比上面兩種方式要複雜一些,步驟如下。

1. 建立一個類實現Callable介面,實現call方法。這個介面類似於Runnable介面,但比Runnable介面更加強大,增加了異常和返回值。
2. 建立一個FutureTask,指定Callable物件,做為執行緒任務。
3. 建立執行緒,指定執行緒任務。
4. 啟動執行緒
  • 1
  • 2
  • 3
  • 4
  • 5

程式碼如下:

package com.roocon.thread.t4;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public classCallableTest {

    public static void main(String[] args) throws Exception {
        Callable<Integer> call = new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                System.out.println("thread start .. ");
                Thread.sleep(2000);
                return 1;
            }
        };

        FutureTask<Integer> task = new FutureTask<>(call);
        Thread t =  new Thread(task);

        t.start();
        System.out.println("do other thing .. ");
        System.out.println("拿到執行緒的執行結果 : " + task.get());
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

執行結果如下:

do other thing .. 
thread start .. 
拿到執行緒的執行結果 : 1
  • 1
  • 2
  • 3

Callable中可以通過範型引數來指定執行緒的返回值型別。通過FutureTask的get方法拿到執行緒的返回值。

基於執行緒池的方式

我們知道,執行緒和資料庫連線這些資源都是非常寶貴的資源。那麼每次需要的時候建立,不需要的時候銷燬,是非常浪費資源的。那麼我們就可以使用快取的策略,也就是使用執行緒池。當然了,執行緒池也不需要我們來實現,jdk的官方也給我們提供了API。

程式碼如下:

package com.roocon.thread.t5;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public classThreadPoolDemo {

    public static void main(String[] args) {

        // 建立執行緒池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        while(true) {
            threadPool.execute(new Runnable() { // 提交多個執行緒任務,並執行

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " is running ..");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

執行結果如下:

pool-1-thread-4 is running ..
pool-1-thread-1 is running ..
pool-1-thread-6 is running ..
pool-1-thread-2 is running ..
pool-1-thread-8 is running ..
pool-1-thread-3 is running ..
pool-1-thread-5 is running ..
pool-1-thread-9 is running ..
pool-1-thread-10 is running ..
pool-1-thread-7 
            
           

相關推薦

java執行6實現方式

多執行緒的形式上實現方式主要有兩種,一種是繼承Thread類,一種是實現Runnable介面。本質上實現方式都是來實現執行緒任務,然後啟動執行緒執行執行緒任務(這裡的執行緒任務實際上就是run方法)。這裡所說的6種,實際上都是在以上兩種的基礎上的一些變形。 繼承

java執行6實現方式執行定時

多執行緒的形式上實現方式主要有兩種,一種是繼承Thread類,一種是實現Runnable介面。本質上實現方式都是來實現執行緒任務,然後啟動執行緒執行執行緒任務(這裡的執行緒任務實際上就是run方法)。這裡所說的6種,實際上都是在以上兩種的基礎上的一些變形。 繼承Thread

Java 線程 三實現方式

() 例子 屬於 周期性 core www object 並且 check Java多線程實現方式主要有三種:繼承Thread類、實現Runnable接口、使用ExecutorService、Callable、Future實現有返回結果的多線程。其中前兩種方式線程執行完後都

【Android】Android開發之常用的loading等待效果實現,仿微博等待動畫。兩實現方式

長期維護的Android專案,裡面包括常用功能實現,以及知識點詳解, 當然還有Java中的知識點。 具體請看github:https://github.com/QQ986945193/DavidAndroidProjectTools 首先大家都知道,當我

購物車3實現方式 

購物車相當於現實中超市的購物車,不同的是一個是實體車,一個是虛擬車而已。使用者可以在購物網站的不同頁面之間跳轉,以選購自己喜愛的商品,點選購買時,該商品就自動儲存到你的購物車中,重複選購後,最後將選中的所有商品放在購物車中統一到付款臺結賬,這也是儘量讓客戶體驗到現實生活中購

Java併發程式設計(二)執行實現方式

Java實現多執行緒的方式 Java實現多執行緒的方式有4種: 繼承Thread方法、實現Runnable介面、實現Callable介面並通過FutureTask建立執行緒、使用ExecutorService。 其中,前兩種執行緒執行結果沒有返回值,後兩種是有返回值的。 1、繼承Th

執行實現方式的區別Thread Runnable

多執行緒兩種實現方式的區別多執行緒的兩種實現方式 Thread Runnable 兩者的區別首先:使用Runnable介面與Thread類相比較,解決了單根繼承的定義侷限性,所以不管後面的區別和聯絡是什麼,至少這一點上就已經下了死定義– 如果要使用一定是用Runnable介面

java執行實現方式的區別,你所不知道的小細節

/* * 建立執行緒時要繼承Runnable介面 * 不要把寶貴的單繼承機會佔有掉 * 兩種方式有點不用,實現Runnable * 介面時多個執行緒中執行一個 * Runnable介面實現類時,run方法資源共享 * 而繼承Thread時,run方

線程兩實現方式的區別

http [] tick 避免 main 單繼承 style 區別 tar 請解釋Thread類與Runnable接口實現多線程的區別?(請解釋多線程兩種實現方式的區別?) 1. Thread類時Runnable接口的子類,使用Runnable接口實現多線程可以避免單繼承局

Java單例模式幾實現方式

開始 名稱 常量 就是 多線程開發 靜態代碼塊 浪費 ack 多線程同步 在平時的工作、學員的學習以及面試過程中,單例模式作為一種常用的設計模式,會經常被面試官問到,甚至筆試會要求學員現場默寫,下面將會就單例模式的實現思路和幾種常見的實現方式進行簡單的分享。

題目24-線程兩實現方式

類重寫 直接 解決方案 做的 子類 是否為空 缺點 多線程同步 弊端 1、多線程兩種實現方式 (1)繼承Thread 定義類繼承Thread 重寫run方法 把新線程要做的事寫在run方法中 創建線程對象 開啟新線程, 內部會自動執行run方法(2)實現Runnable

Java base64加密解密 兩實現方式

1、為什麼要使用Base 64     Base 64主要用途不是加密,而是把一些二進位制數轉成普通字元,方便在網路上傳輸。 由於一些二進位制字元在傳輸協議中屬於 控制字元,不能直接傳送,所以需要轉換一下才可以。由於某些系統中只能使用ASCII字元,Base64

三欄佈局的6實現方式

1.利用浮動 <section class="layout float"> <style type="text/css"> .layout article div { height: 100px; } .layout.float .left

執行---三建立方式例項;以及執行的使用

1、繼承Thread類 繼承Thread類,重寫run方法(即要讓執行緒進行的操作), 建立執行緒例項,呼叫start()方法啟動執行緒。 import java.util.Date; /** * @author: ycz * @date: 2018/11/25 0025

單例模式6實現方式

一:餓漢式public class MyObject { // 立即載入方式==餓漢模式 private static MyObject myObject = new MyObject();

JAVA處理Excel的三實現方式(二)

awm96 2012-05-15 13:49 createExcel(excel6); //modifyExcel(excel2); } static void readExcel(String filePath) throws Exception{ //HSSFWorkb

java動態代理的兩實現方式

  一說到動態代理,我們第一個想到肯定是大名鼎鼎的Spring AOP了。在AOP的原始碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在,各有優劣。jdk動態代理是由java內部的反射機制來實現的,cglib動態代理是通過繼承

java 檔案過濾器的6實現方法

注:執行環境 IDEA package fileTest; /**  * Created by peipei.zhou on 14-7-10.  * 條件:java中有一個FilenameFilter的介面,能夠過濾得到指定型別的檔案或者目錄,其中必須重寫accept(F

java線程四實現方法

pub 主線程 通過 edt dex over main java nds package com.zrun.TestThread; import java.text.SimpleDateFormat; import java.util.Date; import java

[轉載]Java線程的兩實現方式

分享 src 能力 class c89 href ade run fun 轉載:http://baijiahao.baidu.com/s?id=1602265641578157555&wfr=spider&for=pc 前言 線程是程序的一條執行線索,執