第一种继承Thread,重写Thread的run方法:
1.定义一个Mythread类并继承Thread类,重写Thread的run方法,方法内部写具体的业务代码
package com.example.demo;
public class Mythread extends Thread {
@Override
public void run() {
//具体业务代码
for (int i = 0; i < 10; i++) {
System.out.println(getName()+" Hello World "+i);
}
}
}
2.调用Mythread类
package com.example.demo;
public class ThreadDemo {
public static void main(String[] args) {
// 多线程的第一种启动方式继承Thread,成为子类
Mythread mythread = new Mythread();
mythread.setName("Mythread");
mythread.start();
Mythread mythread2 = new Mythread();
mythread2.setName("Mythread2");
mythread2.start();
Mythread1 t = new Mythread1();
t.start();
}
}
第二种定义一个任务类,并实现Runable接口:
1.定义MyRun类
package com.example.demo;
public class MyRun implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" Hello World "+i);
}
}
}
2.调用
package com.example.demo;
public class ThreadDemo {
public static void main(String[] args) {
//第二种实现runable接口,重写Runable接口run方法
MyRun r = new MyRun();
Thread t1 = new Thread(r);//比第一种多出这步(new一个Thread类,并将任务类r传进去)
t1.setName("t1");
t1.start();
Thread t2 = new Thread(r);
t2.setName("t2");
t2.start();
}
}
第三种:特点:可以获取到多线程运行的结果
1.创建一个类MyCallable实现Callable接口2.重写ca11(是有返回值的,表示多线程运行的结果)
3.创建MyCallable的对象(表示多线程要执行的任务);
4.创建FutureTask的对象(作用管理多线程运行的结果)
5.创建Thread类的对象,并启动(表示线程)
package com.example.demo;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += i;
}
return sum;
}
}
package com.example.demo;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
Integer result = futureTask.get();
System.out.println(result);
}
}



三.线程的优先级(setPriority)
java中默认使用抢占式调度(随机性);另外一种是非抢占式调度(按顺序调度)
优先级越大,抢占到cpu概率就越高(但也不是绝对,两个优先级不同的线程同时运行,有可能抵的那个先执行完),java中线程优先级10挡(默认5,数字越大优先级越高)
thread.setPriority(10);
四.守护线程 (thread.setDaemon(true)),说难听点就是备胎线程(守护线程后执行,当其他线程执行完,备胎线程陆续结束,有可能只执行1次备胎线程,也可能10次)

守护线程的应用场景:聊天时,同时传输文件,当关闭聊天时,文件传输也关闭
一下场景也适用
- 垃圾回收:在 Java 等编程语言中,垃圾回收器通常是一个守护线程。它会在程序运行的过程中,定期检查内存中不再被使用的对象,并回收它们占用的内存空间。这样可以自动管理内存,防止内存泄漏,让程序员无需手动释放内存,提高了编程的效率和安全性。
- 日志记录:在应用程序运行时,可能需要将各种日志信息记录下来,如系统错误、用户操作等。可以使用守护线程来定期将内存中的日志数据写入到文件或数据库中。这样,即使主线程结束了,只要还有日志数据需要处理,守护线程就会继续运行,确保日志记录的完整性。
- 定时任务:比如定时备份数据、定时清理缓存等任务。可以创建一个守护线程,让它按照一定的时间间隔来执行这些任务。当程序的主要业务逻辑执行完毕后,守护线程会继续在后台执行定时任务,直到所有非守护线程都结束,它才会自动退出。
- 资源监控:用于监控系统资源的使用情况,如 CPU 使用率、内存使用率、磁盘 I/O 等。守护线程可以定期收集这些资源信息,并在资源使用超过一定阈值时发出警报或采取相应的措施。这样可以帮助管理员及时发现系统问题,保障系统的稳定运行。
- 网络连接管理:在一些网络应用中,需要保持与服务器的长连接,以实现实时数据传输或接收服务器推送的消息。守护线程可以负责监控网络连接的状态,当连接出现异常时自动进行重连操作。同时,它还可以在后台处理一些与网络连接相关的任务,如心跳检测,确保连接的有效性。
五.出让线程 /礼让线程
Thread.yield();//会让运行均匀一些,类似交替执行,但是不是绝对的


六。插入线程 /插队线程
thread.join();

七.线程的生命周期

答案是不会
8.线程的安全问题
2个细节:静态变量+同步代码块

1.是这个类的对象共享这一个变量;2.锁对象(可以是任意Object)必须是唯一的,MyThread.class是这个类的字节码文件,是唯一的(同一个文件夹下不能有2个同名的类),符合要求
9.同步方法


10.lock锁 lock.lock():(当前线程锁住锁,别的线程就拿不到锁);lock.unlock():(释放锁,最好放到finally代码中);finally会在try执行之后立即执行(不管try是否发生异常,或者try中有retrun或者break(finally会在return和break之前执行)


11.死锁 (不是一个知识点,是一个错误:两把锁千万别嵌套使用)


12.生产者和消费者(等待唤醒机制)
多线程中的四部套路:
* 1.循环 while(true) * 2.同步代码快synchronized(Desk.lock) * 3.判断共享数据是否到了末尾(到了末尾)Desk.count == 0 * 4.判断共享数据是否到了末尾(没到末尾,此时执行核心逻辑)else **/
实例
while(true){
synchronized(Desk.lock){
if (Desk.count == 0){
break;
}else {
if (Desk.foodFlag == 0){
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
Desk.count--;
System.out.println(Desk.count);
Desk.lock.notifyAll();
Desk.foodFlag = 0;
}
}
}
}


吃货线程
厨师线程

中间桌子

main方法 启动2个线程

阻塞队列实现等待唤醒机制

实例


线程的6中状态

线程池



1114

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



