1、繼承Thread類
使用便利,但Java是單繼承,繼承了Thread類就不能繼承其它類了
public class ThreadTest extends Thread{
public void run() {
System.out.println(currentThread().getName());
}
public static void main(String[] args) {
ThreadTest thread1 = new ThreadTest();
ThreadTest thread2 = new ThreadTest();
thread1.start();
thread2.start();
}
}
2、實現Runnable接口
使用接口,避免了單繼承的侷限
public class ThreadTest implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
Thread thread1 = new Thread(threadTest, "線程1");
Thread thread2 = new Thread(threadTest, "線程2");
thread1.start();
thread2.start();
}
}
3、使用FutureTask方法
以上兩種創建方法都不帶返回值,而用FutureTask方法創建線程,則有返回值
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadTest implements Callable<String> {
@Override
public String call() {
String name = Thread.currentThread().getName();
return name;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new ThreadTest());
Thread thread1 = new Thread(futureTask, "線程1");
Thread thread2 = new Thread(futureTask, "線程2");
thread1.start();
thread2.start();
System.out.println(futureTask.get());
}
}
同樣,我們創建了兩個線程,都開始運行,但是最終結果卻只有一個返回值,爲什麼?
那是因爲我們使用FutureTask的時候,只能有一個返回值,如果多個線程同時使用,則後執行的線程的返回值,會覆蓋之前的返回值,所以最終只會有一個返回值
4、線程池創建線程
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static java.lang.Thread.sleep;
public class ThreadTest{
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0 ; i < 3 ; i++) {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
}
}
}
由結果我們可以看到,每次執行都是在同一個線程池中使用同一個線程,因爲這種方法可以不創建新的線程,而是一個線程執行完當前任務後,就可以去執行下一個任務,不必新建
(不建議使用Executors去創建,因爲會由於任務過多而導致內存溢出)
建議使用ThreadPooLExecutor的方式去創建線程池
創建守護進程
public class ThreadTest {
public static void main(String[] args) {
Thread daemonThread = new Thread(() -> {
System.out.println("創建一個守護進程");
});
// 設置爲守護進程
daemonThread.setDaemon(true);
daemonThread.start();
}
}
- 如果創建一個用戶線程,那麼即使主線程已經執行完,JVM還要等所有用戶線程也執行完,纔可以退出。
- 如果創建一個守護線程,那麼主線程執行完之後,JVM不用等守護線程退出,而是直接退出。
ps -eaf|grep java // 查看JVM進程
如果你希望在主線程結束後JVM進程馬上結束,那麼在創建線程時可以將其設置爲守護線程,如果你希望在主線程結束後子線程繼續工作,等子線程結束後再讓JVM進程結束,那麼就將子線程設置爲用戶線程