线程概述以及Java中线程的三种创建方式(继承Thread类、实现Runnable接口、实现Callable接口)
线程概述
什么是线程
线程是一个程序内部的一条执行流程
程序如果只有一条执行流程,那么这个程序就是单线程的程序
什么是多线程
多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)
如:12306同时处理多个用户请求,百度网盘下载文件的同时上传文件;再例如:消息通信、淘宝、京东系统都离不开多线程技术
如何在程序中创建出多条线程
Java通过java.lang.Thread
类的对象来代表线程
创建线程的三种方式
1.方式一:继承Thread类
步骤:
相关代码:
package d1_create_thread;
public class ThreadTest1 {
//main方法是由一条默认的主线程执行的
public static void main(String[] args) {
//3.创建MyThread线程类的对象代表一个线程
Thread t = new MyThread();
//4.启动线程(自动执行run方法)
t.start();
for (int i = 0; i <= 5; i++) {
System.out.println("主线程main输出"+i);
}
}
package d1_create_thread;
/**
* 让子类继承Thread线程类
*/
public class MyThread extends Thread{
//2.必须重写Thread类的run方法
@Override
public void run() {
//描述线程的执行任务
for (int i = 0; i <= 5; i++) {
System.out.println("子线程MyThread输出"+i);
}
}
运行结果(每次的运行结果都可能不一样):
优缺点:
多线程注意事项:
1.启动线程必须是调用start方法,不是调用run方法
调用run()方法的话,相当于还是相当于只有一条主线程,会把我们的MyThread对象就当成普通的Java对象,这样就会先执行run方法,再执行main方法。相当于并没有执行多线程
此时的运行结果(每次的运行结果都一样):
为什么呢
t.start()
可以向操作系统CPU注册Thread t = new MyThread();
线程,作为一条单独的执行流程
2.不要把主线程任务放在启动子线程之前
这样会导致永远是主线程的任务先执行完,再执行子线程
2.方式二:实现Runnable接口
步骤:
相关代码:
/**
* 1、定义一个任务类,实现Runnable接口
*/
public class MyRunnable implements Runnable {
//2、重写Runnable的run方法
@Override
public void run() {
//线程要执行的任务
for (int i = 0; i <= 5; i++) {
System.out.println("子线程MyRunnable输出"+i);
}
}
/**
* 实现Runnable接口
*/
public class ThreadTest2 {
public static void main(String[] args) {
//3、创建任务对象
Runnable target = new MyRunnable();
//4、把任务对象交给一个线程对象来处理(Thread中有Runnable相关的构造方法)
//public Thread(Runnable target)
new Thread(target).start();
for (int i = 0; i <= 5; i++) {
System.out.println("主线程main输出"+i);
}
}
运行结果:
优缺点:
(缺点可以忽略不计)
方式二的匿名内部类写法
步骤:
相关代码:
package d1_create_thread;
/**
* 匿名内部类写法
*/
public class ThreadTest2_2 {
public static void main(String[] args) {
//1、直接创建Runnable接口的匿名内部类形式(任务对象),Runnable属于接口,是不能直接new的
Runnable target = new Runnable() {
@Override
public void run() {
//线程要执行的任务
for (int i = 0; i <= 5; i++) {
System.out.println("子线程输出"+i);
}
}
};
new Thread(target).start();
for (int i = 0; i <= 5; i++) {
System.out.println("主线程main输出"+i);
}
}
}
运行结果:
3.方式三:实现Callable接口
前两种线程创建方式都存在的一个问题:
假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果。(因为重写的是public void run()
)
步骤:
代码实现:
/**
* 1、实现Callable接口
*/
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
//2、重写call方法
@Override
public String call() throws Exception {
//描述线程的任务,返回线程执行返回后的结果
//需求:求1~n的和并返回
int sum = 0;
for (int i = 0; i <= n; i++) {
sum += i;
}
return "线程求出1~"+"n"+"的和为"+sum;
}
}
public class ThreadTest3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3、创建一个Callable的对象
Callable<String> call = new MyCallable(100);
//4、把Callable对象封装成FutureTask对象(任务对象)
// 未来任务对象的作用?
// ①是一个任务对象,实现了Runnable
// ②可以在线程执行完毕之后,用未来对象调用get方法获取线程执行完毕后的结果
FutureTask<String> f1 = new FutureTask<String>(call);
//5、把任务对象交给一个Thread对象
new Thread(f1).start();
//6、获取线程执行完毕后返回的结果
//注意:如果执行到这儿,假如上面的线程还没有执行完毕
//这里的代码会暂停,等待上面线程执行完毕后才会获取结果。
String rs = f1.get(); //直接抛出异常
System.out.println(rs);
}
}
运行结果:
FutureTask的API:
优缺点:
优点: 线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强 ; 可以在线程执行完毕后去获取线程执行的结果。
缺点:代码较复杂
参考视频:https://www.bilibili.com/video/BV1g8411o7aj
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/42870.html
如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!