文章目录
创建方式
主要记录一下线程创建的一些方式,后面可以根据不同的需求进行创建。
参考:
死磕 java线程系列之创建线程的8种方式
通过继承Thread类或实现Runnable,Callable接口都可以实现多线程。
采用Runnable,Callable接口的方式创建多线程
(1)线程类只是实现了Runnable接口或Callable接口,还可以继承其它类。
(2)多线程可以共享一个target对象,所以合适多个相同线程来处理同一份资源的情况,从而可以将CPU,代码和数据分开,形成清晰的模型,较好的体现了面向对象的思想。
(3)编程稍微复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法
采用继承Thread类的方法创建多线程
(1)因为多线程类已经继承了Thread类,所以不能在继承其它父类。
(2)编写简单,如果需要访问当前线程,则无须使用Thread.currentThread()方法,直接使用this即可获得当前线程。
1.继承Thread类
启动多线程的步骤如下:
(1)定义Thread 类的子类,并重写该类的run() 方法,该run() 方法的方法体就代表类线程需要完成的任务。因此把run() 方法称为线程执行体。
(2)创建 Thread 子类的实例,即创建线程对象。
(3)调用线程的star()方法来启动该线程。
@Slf4j
public class DemoThread extends Thread{
public static void main(String[] args) {
log.info("主线程开始执行");
DemoThread demoThread = new DemoThread();
demoThread.start();
log.info("主线程执行结束");
}
@Override
public void run() {
log.info("子线程执行");
}
}
2.实现Runnable接口
(1)定义 Runnable 接口的实现类,并重写该接口的run()方法,该run() 方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable 实例类的实例,此实例作为 Thread 的 target 来创建Thread 对象,该Thread 对象才是真正的对象。
@Slf4j
public class DemoRunnable implements Runnable{
public static void main(String[] args) {
log.info("主线程执行");
Thread demoRunnable = new Thread(new DemoRunnable());
demoRunnable.start();
}
@Override
public void run() {
log.info("子线程执行");
}
}
3.匿名内部类
@Slf4j
public class DemoAnonymous {
public static void main(String[] args) {
log.info("主线程执行");
new Thread(new Runnable() {
@Override
public void run() {
log.info("子线程A执行");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
log.info("子线程B执行");
}
}).start();
}
}
4.实现Callabe接口
参考:Java并发编程:Callable、Future和FutureTask
从 java 5 开始,Java 提供了 Callable 接口,该接口是runnable 的增强版,Callable 提供类一个 call() 方法可以作为线程执行体,但是call() 方法的功能更强大。
(1) call() 方法可以有返回值
(2) call() 方法可以声明抛出异常
因此我们完全可以提供一个callable 对象作为Thread的 target ,而该线程的执行体就是该callable 对象的call() 方法。同时 java 5 提供了 Future 接口 来代表Callable 接口里 call() 方法的返回值,并且提供了一个 futureTask 的实现类,该实现类实现类 future 接口,并实现了runnable 接口—可以作为Thread 类的target.
启动步骤如下:
(1)创建callable接口的实现类,并实现call() 方法,该call() 方法将作为线程的执行体,且该call() 方法是有返回值的。
(2)创建 callable实现类的实例,使用 FutureTask 类来包装Callable对象,该FutureTask 对象封装 call() 方法的返回值。
(3)使用FutureTask 对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获取子线程执行结束后的返回值。
@Slf4j
public class DemoCallabe {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// new 接口:这种形式实际上就是生产了该接口的一个实现类,并用该接口来接收
Callable<Integer> call = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.info("子线程结果计算中..");
Thread.sleep(2000);
return 1+8;
}
};
log.info("主线程执行。。。");
FutureTask<Integer> futureTask = new FutureTask<>(call);
Thread t = new Thread(futureTask);
t.start();
//这里会阻塞,必须等待结果返回
Integer integer = futureTask.get();
log.info("得到最终结果为:{}",integer);
}
}
5.定时器Timer
@Slf4j
public class DemoTimer {
public static void main(String[] args) {
Timer timer = new Timer();
log.info("主线程执行...");
//延迟0.3s执行,每隔1s反复执行
timer.schedule(new TimerTask() {
@Override
public void run() {
log.info("子线程执行!");
}
}, 300,1000);
log.info("主线程执行结束...");
}
}
6.线程池
6.1 线程池工具
@Slf4j
public class DemoThreadPool {
public static void main(String[] args) {
// 创建线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);
log.info("主线程执行..");
for (int i = 0; i < 10; i++) {
threadPool.execute(new Runnable() { // 提交多个线程任务,并执行
@Override
public void run() {
log.info("子线程执行.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
6.2 线程池自定义
@Slf4j
public class DemoThreadPool {
public static void main(String[] args) {
//创建等待队列
BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20);
//创建线程池,池中保存的线程数为3,允许的最大线程数为5
ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50, TimeUnit.MILLISECONDS,bqueue);
log.info("主线程执行.");
for (int i = 0; i < 10; i++) {
pool.execute(new Runnable() {
@SneakyThrows
@Override
public void run() {
Thread.sleep(1000);
log.info("子线程执行....");
}
});
}
//关闭线程池
pool.shutdown();
}
}
7.并行计算
使用并行计算的方式,可以提高程序运行的效率,多线程并行执行。
public class DemoStream {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
// 串行,打印结果为12345
list.stream().forEach(System.out::print);
System.out.println();
// 并行,打印结果随机,比如35214
list.parallelStream().forEach(System.out::print);
}
}
8.spring
后续用到再更新…
@Service
public class CreatingThread08Service {
@Async
public void call() {
System.out.println(Thread.currentThread().getName() + " is running");
}
}