frontpage怎么做网站/seo关键词排名优化系统源码
线程概述
什么是线程
线程是一个程序内部的一条执行流程
程序如果只有一条执行流程,那么这个程序就是单线程的程序
什么是多线程
多线程是指从软硬件上实现的多条执行流程的技术(多条线程由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方法@Overridepublic 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方法@Overridepublic 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() {@Overridepublic 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方法@Overridepublic 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