方法一,直接使用 Thread
// 构造方法的参数是给线程指定名字,,推荐给线程起个名字
Thread t1 = new Thread("t1") {
@Override
// run 方法内实现了要执行的任务
public void run() {
log.debug("hello world");
}
};
t1.start();
方法二,使用 Runnable 配合 Thread
把【线程】和【任务】(要执行的代码)分开,Thread 代表线程,Runnable 可运行的任务(线程要执行的代码)
// 创建任务对象
Runnable task2 = new Runnable() {
@Override
public void run() {
log.debug("hello world");
}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐给线程起个名字
Thread t2 = new Thread(task2, "t2");
t2.start();
自己总结思考:
方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开了,用 Runnable 更容易与线程池等高级 API 配合,用 Runnable 让任务类脱离了 Thread 继承体系,更灵活。通过查看源码可以发现,方法二其实到底还是通过方法一执行的!
方法三,实现Callable接口,使用FutureTask 配合 Thread
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 实现多线程的第三种方法可以返回数据
FutureTask futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.debug("多线程任务");
Thread.sleep(100);
return 100;
}
});
// 主线程阻塞,同步等待 task 执行完毕的结果
new Thread(futureTask,"我的名字").start();
log.debug("主线程");
log.debug("{}",futureTask.get());
}
自己总结思考:
Runnable和Callable的区别:
Runnable接口run方法无返回值;Callable接口 call 方法有返回值,支持泛型
Runnable 接口 run 方法只能抛出运行时异常。且无法捕获处理;Callable接口call方法允许抛出异常,可以获取异常信息。
方法四,使用线程池创建、启动线程
通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
log.info(index);
}
});
}
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
for (int i = 0; i <18 ; i++) {
fixedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId()+"编号任务在执行任务,开始时间:"+
System.currentTimeMillis());
try {
Thread.sleep(3000);//
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
scheduledExecutorService.schedule(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId()+"--"+ System.currentTimeMillis()); }
},2, TimeUnit.SECONDS);
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
log.info(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}