这个问题不是很难,这是我面试一个小公司的时候问到的,今天记录下来。
1.第一种,继承Thread类,重写run方法,然后调用start()函数。
案例
public class ExtendsThred extends Thread{
@Override
public void run() {
while (true) {
System.out.println("当前线程名称:" + this.currentThread().getName());
}
}
public static void main(String[] args) {
//extendThread线程
new ExtendsThred().start();
//main线程
while (true) {
System.out.println("当前线程名称:" + currentThread().getName());
}
}
}
2.第二种,实现Runnable接口,借助Thread类,把Runnale实现类传入Thread的构造函数,然后条用start(),这是我们常用的一种方法。
案例
public class RunnableThreadTest {
public class RunnableThread implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("我是Runnable线程"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
//runnable线程
RunnableThread runnable = new RunnableThreadTest().new RunnableThread();
new Thread(runnable).start();
//mian线程
while (true) 再
System.out.println("我是main线程"+Thread.currentThread().getName());
}
}
}
3.第三种,使用内部类的方式,直接new Thread,然后实现run方法,或者new 一个Runnable接口,实现run方法,然后传入Thread的构造方法中,调用start()
案例:
public class InnerThread {
public static void main(String[] args) {
//使用Runnable
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("当前线程:" + Thread.currentThread().getName());
}
}
}).start();
//使用Thread
new Thread(){
@Override
public void run(){
while (true) {
System.out.println("当前线程:" + Thread.currentThread().getName());
}
}
}.start();
//main线程
while (true) {
System.out.println("main");
}
}
}
4.第四种:实现Callable接口,然后使用FutureTask包装,再借助Thread类实现。
案例:
public class CallableThreadTest {
//callable的call方法有返回值
public class CallableThread<String> implements Callable<String> {
@Override
public String call() throws Exception {
while (true) {
System.out.println("当前线程:" + Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
//使用Callable、FutureTask包装器,借助Thread实现多线程
CallableThread<String> callableThread = new CallableThreadTest().new CallableThread<>();
FutureTask<String> task = new FutureTask<>(callableThread);
new Thread(task).start();
while (true) {
System.out.println("当前线程:" + Thread.currentThread().getName());
}
}
}
5.第五种,使用线程池技术,ExecutorService,可以执行有返回值的线程任务,也可以执行没有返回值的线程任务,有返回值的任务使用Callable接口,没有返回值的任务使用Runnable接口
案例
public class ExecutorThreadTest {
//无返回值线程
public class RunnableThread implements Runnable{
@Override
public void run() {
while (true) {
System.out.println("当前为Runnable接口任务线程");
}
}
}
//有返回值线程
public class CallableThread implements Callable<Object> {
@Override
public Object call() throws Exception {
while (true) {
System.out.println("当前为Callable接口任务线程");
}
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//通过工具类获得线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//执行无返回值的线程任务
executorService.submit(new ExecutorThreadTest().new RunnableThread());
//执行有返回值的线程任务,一个Future存放一个线程返回的结果。get()方法是阻塞的,没有获得结果就会一直等待。
for (int i = 0; i < 5; i++) {
Future result = executorService.submit(new ExecutorThreadTest().new CallableThread());
System.out.println((String) result.get());
}
}
}
6.第六种:基于定时器的方法,使用Timer来完成。可以使线程任务在特定的时间执行,或者每隔一段时间就执行一次。
案例:
public class TimerThread {
public static void main(String[] args) throws ParseException {
//指定2021-1-23 03:22:45执行改线程
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = format.parse("2021-1-23 03:22:45");
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("timer执行");
}
}, date);
//每2秒执行一次
Timer timer1 = new Timer();
timer1.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("每隔2秒执行一次");
}
},new Date(),2000);
}
}
当然,我们在实际的项目开发中,一般是使用线程池技术来完成任务。