1、继承Thread创建线程

继承java.lang.Thread类,重写run()方法,在run()方法中实现运行在线程上的代码,调用start()方法开启线程
本质上是实现了Runnable接口的一个实例,代表一个线程的实例,启动线程的唯一方法是通过start()方法,它是一个native方法,启动一个新线程,并执行run()方法

class MyThread extends Thread {
	@Override
	public void run() {
		System.out.println("我是继承Thread创建的线程:" + Thread.currentThread().getName());
	}
}

public static void main(String[] args) throws InterruptedException {
	System.out.println("我是主线程:" + Thread.currentThread().getName());
	new MyThread().start();
	new MyThread().start();
}

运行结果

我是主线程:main
我是继承Thread创建的线程:Thread-0
我是继承Thread创建的线程:Thread-1

2、实现Runnable创建线程

重写run()方法,无返回值

class MyRunnable implements Runnable {
	@Override
	public void run() {
		System.out.println("我是实现Runnable创建的线程:" + Thread.currentThread().getName());
	}
}

public static void main(String[] args) throws InterruptedException {
	System.out.println("我是主线程:" + Thread.currentThread().getName());
	new Thread(new MyRunnable()).start();
	new Thread(new MyRunnable()).start();
}

运行结果

我是主线程:main
我是实现Runnable创建的线程:Thread-0
我是实现Runnable创建的线程:Thread-1

3、实现Callable创建线程

重写call()方法,有返回值,可以抛出异常被捕获

class MyCallable implements Callable<String> {
	@Override
	public String call() throws Exception {
		return "我是实现Callable创建的线程:" + Thread.currentThread().getName();
	}
}

public static void main(String[] args) throws InterruptedException {
	System.out.println("我是主线程:" + Thread.currentThread().getName());
	MyCallable myCallable1 = new MyCallable();
	MyCallable myCallable2 = new MyCallable();
	FutureTask<String> futureTask1 = new FutureTask<>(myCallable1);
	FutureTask<String> futureTask2 = new FutureTask<>(myCallable2);
	new Thread(futureTask1).start();
	new Thread(futureTask2).start();
	try {
		System.out.println(futureTask1.get());
		System.out.println(futureTask2.get());
	} catch (ExecutionException e) {
		e.printStackTrace();
	}
}

运行结果

我是主线程:main
我是实现Callable创建的线程:Thread-0
我是实现Callable创建的线程:Thread-1

4、通过线程池创建线程创建线程

线程和数据库连接这些资源都是非常宝贵的,如果我们每次需要的时候创建,不需要的时候销毁,是非常浪费的,我们可以使用缓存策略,也就是使用线程池

public static void main(String[] args) throws InterruptedException {
	System.out.println("我是主线程:" + Thread.currentThread().getName());
	ExecutorService executorService = Executors.newFixedThreadPool(2);
	executorService.execute(() -> System.out.println("我是线程池创建的线程:" + Thread.currentThread().getName()));
	executorService.execute(() -> System.out.println("我是线程池创建的线程:" + Thread.currentThread().getName()));
}

运行结果

我是主线程:main
我是线程池创建的线程:pool-1-thread-1
我是线程池创建的线程:pool-1-thread-2

5、通过匿名内部类创建线程

下面两种写法,本质上都是实现Runnable接口,重写run()方法,第二种使用的Lambda表达式

public static void main(String[] args) throws InterruptedException {
	System.out.println("我是主线程:" + Thread.currentThread().getName());
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("我是匿名内部类创建的线程:" + Thread.currentThread().getName());
			}
		}).start();
		new Thread(() -> System.out.println("我是匿名内部类创建的线程:" + Thread.currentThread().getName())).start();
}

运行结果

我是主线程:main
我是匿名内部类创建的线程:Thread-0
我是匿名内部类创建的线程:Thread-1