Java Java中三种常见的创建线程形式
1.继承Thread类,重写该类的run()方法。
先创建一个线程类对象,调用start方法启动新线程。此处调用start方法不代表线程立马运行,start方法只是把该线程加入到操作系统的任务队列中,当被操作系统的任务调度机制调度到后才执行。
注意:如果使用线程对象调用run方法,则此时run方法相当于对象的普通方法。此处就没有创建线程,依然在原有线程中
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("自定义线程," + i);
}
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1.start();
myThread2.start();
for (int i = 0; i < 100; i++) {
System.out.println("main线程," + i);
}
}
}
2.实现Runnable接口,并重写该接口的run()方法
该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "," + i);
}
}
}
public class Test {
public static void main(String[] args) {
// 没有start方法
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
// 创建一个线程对象
Thread t1 = new Thread(myThread1);
t1.start();
Thread t2 = new Thread(myThread2);
t2.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "," + i);
}
}
}
3.使用Callable和Future接口创建线程。
先自定义类实现Callable接口;实现call方法,该方法有返回值类型,使用FutureTask类来包装Callable实现类,以FutureTask对象作为Thread对象的target来创建线程。
FutureTask类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。这是一种适配器模式。
public class MyThread implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "," + i);
Thread.sleep(10);
}
return "100";
}
}
public class Test {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 没有start方法
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
FutureTask<String> future1 = new FutureTask(myThread1);
FutureTask<String> future2 = new FutureTask(myThread2);
// 创建一个线程对象
Thread t1 = new Thread(future1);
t1.start();
Thread t2 = new Thread(future2);
t2.start();
Thread.sleep(2000);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "," + i);
}
}
}
4、面试说以上三种就够了,但还有第四种线程池的方式。
Java通过Executors提供四种线程池,分别为:
- newSingleThreadExecutor (老板就是工人,整个工厂只有一个工人)。创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
- newFixedThreadPool (全部是正式工)。创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 。创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
- newCachedThreadPool (全部是临时工)。创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。