JAVA的线程
JAVA的线程
1.1线程与进程
进程:是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如:CPU 时间,内存空间,文件,输入输出设备的使用权等等。
线程:线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
一个进程至少包含一个线程,如下图:
1.2JAVA创建线程的方式
- 继承Thread类方式
/**
* @Author:yml
* @Data:2022/4/19
*/
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("继承Thread方式");
}
}
如上:继承Thread类,重写run方法,调用当前线程需要调用start()方法。
/**
* @Author:yml
* @Data:2022/4/19
*/
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
- 实现Runnable接口
/**
* @Author:yml
* @Data:2022/4/19
*/
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable方式");
}
}
- 实现Callable接口(具有返回值的线程)
/**
* @Author:yml
* @Data:2022/4/19
*/
public class MyThread implements Callable<String> {
@Override
public String call() throws Exception {
return "具有返回值的线程";
}
}
使用方式也有差别:
/**
* @Author:yml
* @Data:2022/4/19
*/
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
FutureTask<String> futureTask = new FutureTask<>(myThread);
Thread thread = new Thread(futureTask);
thread.start();
try {
String s = futureTask.get();
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行需要借助FutureTask类记性封装,返回值使用FutureTask的get方法进行获取。
1.3线程的生命周期
线程的5种状态
- new 新建状态
使用new关键字和Thread类或者起子类创建一个线程对象后,该线程对象就处于新建状态。这个状态一直保持程序start()这个线程。 - Runnable 就绪状态(可运行状态)
当其他线程调用了该线程对象的start()方法后,该线程就进入就绪状态。处于就绪状态的线程,随时可能被CPU调度执行。 - Running 运行状态
线程获取CPU执行权限进行执行,去执行run()方法,此时线程处于运行状态,需要注意的是,线程只能从就绪状态进入运行状态。 - Blocked 阻塞状态
阻塞状态是线程因为某种原因放弃CPU执行执行资格,暂时停止运行。知道线程进入就绪状态,才有机会转到运行状态。
阻塞状态分为三种情况:
1.等待阻塞:通过调用线程的wait()方法,让线程等带某工作的完成
2.同步阻塞:线程在获取synchronized同步锁失败,它会进入同步阻塞状态
3.其他阻塞:通过调用线程的sleep()或者join()或发出I/O请求时,线程会进入到阻塞状态。当sleep状态超时、join()等待线程终止或超时、或I/O处理完毕时,线程重新转入就绪状态。 - Dead 死亡状态
线程执行完了或因异常退出了run()方法,该线程结束生命周期。
1.4线程常用方法
1.线程停止
线程停止的方法JDK提供了stop()和destory(),这两种方法已经废弃,不推荐使用这种方式。推荐使用一个标识位让线程自己停下来。
2.sleep和wait的区别
- sleep()是属于Thread类,wait()是属于Object类
- sleep()不依赖同步方法,而wait()依赖,并且sleep()不会释放锁,wait会释放锁
- sleep()不需要唤醒 超时结束就会进入就绪状态,wait需要notify()或者notifyAll()唤醒才会进入就绪状态
3.join()
当线程A调用了线程B的join方法,线程A就会一直等待,知道线程B执行完成。
join()默认为join(0)
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
join(long millis)-> join(0)表示永远等待没有超时时间,底层还是调用wait()实现,当线程死亡时会调用notifyAll()
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
3.线程礼让--yeild()
不会释放锁,主要让当前线程让出CPU时间片,当前线程进入就绪队列,重新与其他线程竞争CPU时间片。
4.获取线程状态--getState
线程状态,线程可以处于以下状态之一:
- NEW 尚未启动的线程处于此状态(创建状态)
- RUNNABLE 在Java虚拟机中执行的线程处于此状态(运行状态)
- BLOCKED 被阻塞等待监视器锁定的线程处于此状态(阻塞状态)
- WAITING 正在等待另一个线程执行特定动作的线程处于此状态(阻塞状态)
- TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态(阻塞状态)
TERMINATED 已退出的线程处于此状态(死亡状态)
一个线程可以在给定时间点处于一个状态,这些状态是不反映任何操作系统线程状态的的虚拟机状态
5.线程的优先级--setPriority
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
优先级范围从1-10,使用getPriority来获取优先级,setPriority来改变优先级
需要注意的是优先级高并不一定优先执行,线程的执行顺序真正取决于CPU调度器
6.设置守护线程--setDaemon
线程分为用户线程和守护线程,常见的守护线程:垃圾回收机制
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤