第三种方式:使用内部类的方式
这并不是一种新的实现线程的方式,只是另外的一种写法。比如有些情况我们的线程就想执行一次,以后就用不到了。那么像上面两种方式(继承Thread类和实现Runnable接口)都还要再定义一个类,显得比较麻烦,我们就可以通过匿名内部类的方式来实现。使用内部类实现依然有两种,分别是继承Thread类和实现Runnable接口。
/**
* 匿名内部类的方式创建线程
*/
public class CreateThread_Anonymous {
public static void main(String[] args) {
// 基于子类的方式
new Thread() {
@Override
public void run() {
while (true) {
printThreadInfo();
}
}
}.start();
// 基于接口的实现
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
printThreadInfo();
}
}
}).start();
}
/**
* 输出当前线程的信息
*/
private static void printThreadInfo() {
System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
运行结果:
第四种方式:定时器
在应用中经常需要定期执行一些操作,比如要在凌晨的时候汇总一些数据,比如要每隔10分钟抓取一次某个网站上的数据等等,总之计时器无处不在。
在Java中实现定时任务有很多种方式,JDK提供了Timer类来帮助开发者创建定时任务,另外也有很多的第三方框架提供了对定时任务的支持,比如Spring的schedule以及著名的quartz等等。
- 指定时间点执行
/**
* 定时任务
*/
public class CreateThread2_Timer {
private static final SimpleDateFormat format =
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
public static void main(String[] args) throws Exception {
// 创建定时器
Timer timer = new Timer();
// 提交计划任务
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("定时任务执行了...");
}
}, format.parse("2017-10-11 22:00:00")); //指定执行的时间
}
}
运行结果:
2.间隔时间重复执行
/**
* 定时任务
*
*/
public class CreateThread2_Timer {
public static void main(String[] args){
// 创建定时器
Timer timer = new Timer();
// 提交计划任务
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("定时任务执行了...");
}
},new Date(), 1000); //指定间隔的时间
}
}
运行结果:
第五种方式:Future模式(带返回值的线程实现方式)
我们发现上面提到的不管是继承Thread类还是实现Runnable接口,发现线程执行完毕之后并无法获得线程的返回值。
但是使用这种方式创建线程比上面两种方式要复杂一些,步骤如下。
创建一个类实现Callable接口,实现call方法。这个接口类似于Runnable接口,但比Runnable接口更加强大,增加了异常和返回值。
创建一个FutureTask,指定Callable对象,做为线程任务。
创建线程,指定线程任务。
启动线程
代码如下:
/**
* 带返回值的方式
*/
public class CreateThreadDemo3_Callable {
public static void main(String[] args) throws Exception {
// 创建线程任务
Callable<Integer> call = () -> {
System.out.println("线程任务开始执行了....");
Thread.sleep(2000);
return 1;
};
// 将任务封装为FutureTask
FutureTask<Integer> task = new FutureTask<>(call);
// 开启线程,执行线程任务
new Thread(task).start();
// ====================
// 这里是在线程启动之后,线程结果返回之前
System.out.println("这里可以为所欲为....");
// ====================
// 为所欲为完毕之后,拿到线程的执行结果
Integer result = task.get();
System.out.println("主线程中拿到异步任务执行的结果为:" + result);
}
}
运行结果:
Callable中可以通过范型参数来指定线程的返回值类型。通过FutureTask的get方法拿到线程的返回值。
第六种方式:基于线程池的方式
我们知道,线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。
/**
* 线程池
*/
public class CreateThreadDemo4_ThreadPool {
public static void main(String[] args) throws Exception {
// 创建固定大小的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
while (true) {
// 提交多个线程任务,并执行
threadPool.execute(new Runnable() {
@Override
public void run() {
printThreadInfo();
}
});
}
}
/**
* 输出当前线程的信息
*/
private static void printThreadInfo() {
System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
运行结果:
欢迎留言讨论。