线程一:概念、创建线程
1、线程相关概念
并发: 在同一时刻,有多个任务在多个CPU上同时执行。
并行: 在同一时刻,有多个任务在单个CPU上交替执行。
进程: 进程简单地说就是在多任务操作系统中,每一个单独执行的程序
线程: 线程是程序运行的基本执行单元; 也就是应用程序中做的事情
多线程:
- 是指从软件或者硬件上实现多个线程并发执行的技术
- 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。
2、创建线程方式一:继承Thread
Java使用java.lang.Thread
类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。
创建使用:
- 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
- 创建Thread子类的实例,即创建了线程对象
- 调用线程对象的start()方法来启动该线程
代码体现:
【测试类】
public class Demo01 {
public static void main(String[] args) {
//创建自定义线程对象
MyThread mt = new MyThread("新的线程!");
//开启新线程
mt.start();
//在主方法中执行for循环
for (int i = 0; i < 200; i++) {
System.out.println("main线程!"+i);
}
}
}
【自定义线程类】
public class MyThread extends Thread {
//定义指定线程名称的构造方法
public MyThread(String name) {//调用父类的String参数的构造方法,指定线程的名称
super(name);
}
public MyThread() {//不指定线程的名字,线程有默认的名字Thread-0
}
// 重写run方法,完成该线程执行的逻辑
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println(getName()+":正在执行!"+i);
}
}
}
可以使用匿名内部类
3、创建线程方式二:实现Runnable
采用java.lang.Runnable
也是非常常见的一种,我们只需要重写run方法即可。
创建使用:
- 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
- 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
- 调用线程对象的start()方法来启动线程。
代码体现:
【测试类】
public class Demo {
public static void main(String[] args) {
//创建自定义类对象 线程任务对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t = new Thread(mr, "小强");
t.start();
for (int i = 0; i < 20; i++) {
System.out.println("旺财 " + i);
}
}
}
【自定义线程类】
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
可以使用匿名内部类
4、创建线程方式三:实现Callable接口
【测试类】
public class MyThread03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thread.currentThread().setName("主线程");
// 创建Callable的实现类对象
MyCallable myCallable = new MyCallable();
// 中间者 , 作为Thread类和Callable接口的桥梁
FutureTask<String> task = new FutureTask<>(myCallable);
Thread t1 = new Thread(task , "线程1");
// 开启线程
t1.start();
// FutureTask类中存在一个get方法 , 可以获取call方法最后的返回值
// get方法必须放在开启线程之后
String s = task.get();// 具备阻塞作用!
System.out.println(s);// "答应"
// main线程中的任务
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
【自定义线程类】
// 1 自己写一个类实现Callable接口
class MyCallable implements Callable<String> {
// 编写任务的方法
// 此方法的返回值 , 是当前线程执行完毕,结果数据
@Override
public String call() throws Exception {
for (int i = 1; i <= 100; i++) {
System.out.println("求爱" + i + "次!");
}
return "答应";
}
}
5、三种方法的区别
- 继承Thread
优点 : 编程比较简单,可以直接使用Thread类中的方法
缺点 :
1 可扩展性较差,不能再继承其他的类
2 任务方法run() , 没有返回值 , 不能抛出异常只能捕获异常
- 实现Runnable : 相对于使用较多!
优点 : 扩展性强,实现该接口的同时还可以继承其他的类。
缺点 :
1 编程相对复杂,不能直接使用Thread类中的方法
2 任务方法run() , 没有返回值 , 不能抛出异常只能捕获异常
- 实现Callable
优点 :
1 扩展性强,实现该接口的同时还可以继承其他的类。
2 当任务执行完之后,可以返回一个结果值
3 call方法中如果出现了异常既可以抛出也可以捕获
缺点 :
1 编程相对复杂
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~