目录
什么是线程
Java中线程的使用
线程的实现
并运行一个线程
如何为线程命名
查看当前jvm中运行的所有线程
线程池的基本使用
线程休眠
设置线程的优先级(都仅供参考)
线程的插队
线程的中断
线程的分类
线程的状态
什么是线程
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。在多核CPU中,利用多线程可以实现真正意义上的并行执行。一个进程的所有任务都在线程中执行,进程要想执行任务,必须得有线程,进程至少要有一条线程,程序启动会默认开启一条线程,这条线程被称为主线程或 UI 线程。
一个程序有多个进程,一个进程有多个线程
- 单线程:单线程指的是程序只有一个执行线程,按照顺序逐个执行任务。当一个任务执行完毕后,才能执行下一个任务。
- 多线程:多线程指的是程序可以同时执行多个线程,每个线程可以独立执行任务。多线程可以同时处理多个任务,提高程序的执行效率。
Java中线程的使用
线程的实现
线程的实现有三种方法
1.实现Runnable接口
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
});
2.实现Callable接口(有返回值)
class SubTask implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return null;
}
}
并运行一个线程
1.创建线程,通过Thread类来创建一个子线程
// 创建子线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (char i ='A';i<'Z';i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
},"子线程");
2.运行子线程
thread.start();
3.输出结果为
如何为线程命名
1.在创建线程时命名
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
},"子线程1");
2.通过setname方法来命名
Thread thread = new Thread();
thread.setName("子线程")
查看当前jvm中运行的所有线程
public static void main(String[] args) {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
for(ThreadInfo threadInfo:threadInfos){
System.out.println(threadInfo.getThreadId()+"-------------"+threadInfo.getThreadName());
}
}
线程池的基本使用
案例:实现10000以内的数字相加之和
ExecutorService executorService = Executors.newFixedThreadPool(5);
int sum = 0;
for (int i = 1;i<=10000;i+=2000){
// 向线程池提交一个线程任务
// 线程池分配一个空闲线程执行任务
Future<Integer> submit = executorService.submit(new SubTask(i, i + 2000));
Integer num = submit.get();
sum+=num;
}
System.out.println(sum);
executorService.shutdown();
- ExecutorService 线程池的统一实现接口
- Executors 线程池的工具类
- newFixedThreadPool(5) 固定线程池数量
线程休眠
线程休眠,是由用户控制的(用户主动调用相关方法才能使线程睡眠),睡眠恢复则是自动完成的,睡眠时间到了则恢复到就绪态,睡眠时线程不会释放对象锁。
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
注意:线程的休眠需要抛出异常
设置线程的优先级(都仅供参考)
多个线程之间一般是进行抢占式的进行,谁先抢到谁就先执行
有两种方法
1.线程对象.setPriority(1) :1最小,10最大
2.Thread.yield() :表示该线程在抢占后让出
线程的插队
通过方法 :线程对象.join();
public static void main(String[] args) {
MyTask task = new MyTask();
Thread thread1 = new Thread(task,"线程1");
// 设置线程的优先级 (仅供参考)
thread1.start();
// 子线程的插队 调用join方法进行插队
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束");
}
join()方法通过wait()实现,是被插队的线程(主线程),处于等待状态。
线程的中断
通过interrupt()方法来使线程进入中断,同时要想线程进入中断,该线程必须有能接受中断的状态,也就是该线程必须有进行过join等方法抛出过InterruptedException异常
同时也可以通过Thread.currentThread()的isInterrupted()方法来判断当前线程是否中断
是则返回ture,否则返回false
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程开始执行");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 检查当前线程是否处于中断状态,Thread.currentThread().isInterrupted()是则返回ture,不是则为false
while (!Thread.currentThread().isInterrupted()){
System.out.println("没中断");
}
System.out.println("子线程结束");
}
});
t.start();
}
线程的分类
- 用户线程:由应用程序开发者创建和管理,不依赖于操作系统。
- 守护线程:在后台运行,通常用于执行后台任务。
线程的状态
通过Thread.state的这个枚举类的底层代码我们可以发现,线程共有六种状态
- 新建状态(New):当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新建状态。处于新建状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的。
- 运行状态(Runnable):通过调用线程实例的start()方法来启动线程使线程进入就绪状态。处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPU。
- 阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞状态。处于Blocking状态的线程仍然是活着的。
- 等待状态(waiting):无期限等待另一个线程执行特定操作的线程处于此状态。
定时等待状态(timed_waiting):等待另一个线程执行操作达到指定等待时间的线程处于此状态。
终止状态(Terminated):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡状态。