先给出图片版(标出关键代码),再给出文字版!
话不多说,直接上示例代码吧!
创建线程之继承Thread类

给出文字版:
/**
* 创建线程 --- 测试
*
* @author JustryDeng
* @date 2018/10/11 14:52
*/
public class CreatThreadByExtendsThread {
public static void main(String[] args) {
// 获取该线程实例
MyThread myThread = new MyThread();
// 运行该线程
myThread.start();
//主线程同时输出,以作对比
for (int i = 1; i <= 100; i++) {
Thread.currentThread().setName("main线程");
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
}
/**
* 创建线程 -> 继承Thread类,重写run方法
*
* @date 2018/10/11 14:54
*/
class MyThread extends Thread{
@Override
public void run() {
this.setName("JustryDeng线程");
for (int i = 1; i <= 100; i++) {
System.out.println(this.getName() + "->" + i);
}
}
}
注:这里只给出最基本的示例,灵活变形使用即可。
运行主函数,输出内容为:

创建线程之实现Runnable接口

给出文字版:
/**
* 创建线程 ---- 测试
*
* @date 2018/10/11 14:54
*/
class Rtest {
public static void main(String[] args) {
// 获取该线程实例
CreatThreadByImplementsRunnable ctb = new CreatThreadByImplementsRunnable();
Thread thread = new Thread(ctb, "R线程");
// 运行该线程
thread.start();
//主线程同时输出,以作对比
for (int i = 1; i <= 100; i++) {
Thread.currentThread().setName("main线程");
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
}
/**
* 创建线程 -> 实现Runnable接口,重写run方法;
*
* @author JustryDeng
* @date 2018/10/11 14:52
*/
public class CreatThreadByImplementsRunnable implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
}
注:这里只给出最基本的示例,灵活变形使用即可。
运行主函数,输出内容为:

创建线程之实现Callable<V>接口

给出文字版:
import java.util.Random;
import java.util.concurrent.*;
/**
* 创建线程 ---- 测试
*
* @date 2018/10/11 14:54
*/
class Ctest {
private static Integer count;
public static void main(String[] args) {
fa1();
// fa2();
}
public static void fa1(){
// 获取该线程实例
CreatThreadByImplementsCallable ctbic = new CreatThreadByImplementsCallable();
ctbic.setName("C线程!");
// 使用Executors调度器,创建有3个空闲线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 将Callable<V>实现类的实例提交到线程池中,如果线程池中有空的线程,那么执行此实例的call()方法
executorService.submit(ctbic);
// 线程池中的所有线程都运行完毕后,关闭线程池
executorService.shutdown();
//主线程同时输出,以作对比
for (int i = 1; i <= 100; i++) {
Thread.currentThread().setName("main线程");
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
public static void fa2(){
// 获取该线程实例
CreatThreadByImplementsCallable ctbic = new CreatThreadByImplementsCallable();
ctbic.setName("C线程!");
// 使用Executors调度器,创建有3个空闲线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 将Callable<V>实现类的实例提交到线程池中,如果线程池中有空的线程,那么执行此实例的call()方法
// Future<V>接口与Callable<V>搭配使用,future.get()用于等待call()方法执行完毕并接受call()方法的返回值
Future<Integer> future = executorService.submit(ctbic);
try {
// 注意:future.get()会使当前线程阻塞,一致等到call()执行完毕返回返回值之后,当前线程再往下执行
System.out.println("ctbic实例的call()方法的返回值为:" + future.get());
// 线程池中的所有线程都运行完毕后,关闭线程池
executorService.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//主线程同时输出,以作对比
for (int i = 1; i <= 100; i++) {
Thread.currentThread().setName("main线程");
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
}
/**
* 创建线程 -> 实现Callable<V>接口,call方法
* 注:指定泛型,就是制定call()方法的返回值类型
* 注:不指定泛型,那么默认泛型为Object
*
* @author JustryDeng
* @date 2018/10/11 14:52
*/
public class CreatThreadByImplementsCallable implements Callable<Integer> {
/* 线程名 */
private String name;
public void setName(String name) {
this.name = name;
}
/**
* 相比起其他两种方式,此方式的优势在于:
* 1. 有返回值
* 2. 可以抛出异常
*/
@Override
public Integer call() throws Exception {
// 随机获得[0,1000)中的整数
Integer num = new Random().nextInt(1000);
if(num <= 3){
throw new Exception();
}
//主线程同时输出,以作对比
for (int i = 1; i <= num; i++) {
System.out.println(name + "->" + i);
}
return num;
}
}
注:类似的还有FutureTask<V>,FutureTask<V>就像一个Runnable、Callable<V>、Future<V>的集合版,感兴趣的可
自己去了解一下,这里就不再细说。
注:这里只给出最基本的示例,灵活变形使用即可。
注:ExecutorService的shutdown();方法是指:当线程池中的所有线程(包括排着队的)都执行完毕后,再关闭线程池。如果
执行到shutdown()方法时,线程池中的所有线程正在执行任务,且还有100个任务排着队;那么只有当线程池中的线程
把这100个排着队的线程执行完毕之后,才会关闭线程池。P.S.此处不易解释,推荐直接查看ExecutorService源码(注释)。
注:ExecutorService的shutdownNow();方法是指:当线程池中的所有(正在执行着的)线程都执行完毕后,再关闭线程池。
如果执行到shutdownNow()方法时,线程池中的所有线程正在执行任务,且还有100个任务排着队;那么当线程中的
线程执行完正在执行的线程后,就不再“接新的线程任务”了,等到线程中的所有线程都空闲下来了,那么直接关闭线程池,
并不理会那100个排着队的线程任务,让他们死去吧。P.S.此处不易解释,推荐直接查看ExecutorService源码(注释)。
注:shutdown()、shutdownNow()方法都不会阻塞当前所在线程。
主函数中将fa2()注释掉,运行fa1(),控制台输出结果为:

主函数中将fa1()注释掉,运行fa2(),控制台输出结果为:

给出一个多线程使用Callable<V>、Future<V>的实例参考:

三种方式的比较

注:虽然实现Callable<V>接口开启线程的方式,相对执行效率低;但是对比起带来的效益,低那么点效率是完全值得的。
笔者将本人多线程一栏中博客涉及到的所有代码示例(Lock分开放在一个专门的项目、synchronized的代码附在该文章末尾),放在GIT上了(链接见本文末),这里先给出一个所涉及内容图:

本文详细介绍了在Java中创建线程的三种常见方法:继承Thread类、实现Runnable接口及实现Callable接口。通过示例代码展示了每种方法的具体实现过程,并对比了它们之间的优劣。
14万+

被折叠的 条评论
为什么被折叠?



