Java创建线程的四种方式,以及创建守护线程

Source

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进程结束,那么就将子线程设置为用户线程

发布了16 篇原创文章 · 获赞 16 · 访问量 4917