【后端修行之JUC】一些关于Java线程基础理解

本文用于记录学习黑马JUC课程后,个人认为有价值的笔记,核心内容均围绕标题展开。既做一个学习的记录,同时也做一个沟通交流,欢迎各位大佬互动~

创建和运行线程

方法一:使用Thread类创建对象(覆盖run,run方法内包含需要运行的代码,start方法启动线程)

方法二:使用Runnable(可运行的任务)配合Thread(线程和任务分离), Runnable接口为函数式接口

Runnable runnable = new Runnable(){

public void run(){

//要执行的任务

}

}

Thread t = new Thread(runnable,’名字’);

t.start();

方法一和方法二原理:方法一是重写Thread的run方法,而方法二是将runnable对象传递给Thread的方法(更好和线程池的高级api.)

方法三:FutureTask配合Thread,FutureTask能够接受Callable类型的参数,用来处理有返回结果的情况.

​​​​​​​线程运行原理

线程运行原理: 类加载之后,代码缓存在方法区,等待cpu分配时间片,创建相应的线程(线程调度器负责创建和调度),在占用时间片的过程中,线程根据方法执行和调用的情况创建和删除相应的栈帧,期间伴随着或被动或主动的原因进行上下文切换,最终代码执行完毕线程关闭.

上下文切换:指由于一些原因cpu不在执行当前线程,转而执行另一个线程的代码.

导致上下文切换的原因有4个(3被动1主动):①线程的时间片用完;②产生垃圾回收;③有更高优先级的线程需要进行;④线程调用了sleep,yield,wait,join,park,synchronized,lock等方法

​​​​​​​常见方法

Thread 类 API:

方法

说明

public void start()

启动一个新线程(仅进入就绪状态,非立刻运行),Java虚拟机调用此线程的 run 方法.只能用一次,多次调用会产生错误.

public void run()

线程启动后调用该方法(被重写或者使用runnable对象)

public void setName(String name)

给当前线程取名字

public void getName()

获取当前线程的名字

线程存在默认名称:子线程是 Thread-索引,主线程是 main

public static Thread currentThread()

获取当前线程对象,代码在哪个线程中执行

public static void sleep(long time)

让当前线程休眠多少毫秒再继续执行

Thread.sleep(0) : 让操作系统立刻重新进行一次 CPU 竞争

public static native void yield()

提示线程调度器让出当前线程对 CPU 的使用

public final int getPriority()

返回此线程的优先级

public final void setPriority(int priority)

更改此线程的优先级,常用 1 5 10

public void interrupt()

中断这个线程,异常处理机制

public static boolean interrupted()

判断当前线程是否被打断,清除打断标记

public boolean isInterrupted()

判断当前线程是否被打断,不清除打断标记

public final void join()

等待这个线程结束

public final void join(long millis)

等待这个线程死亡 millis 毫秒,0 意味着永远等待

public final native boolean isAlive()

线程是否存活(还没有运行完毕)

public final void setDaemon(boolean on)

将此线程标记为守护线程或用户线程

getState()

获取线程状态, NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED

start/run: ①区别; ②start改变进程状态; ③重复调用start

sleep: ①让当前线程从running进入到timed waiting状态; ②其他线程可用interrupt方法打断正在睡眠的线程,但会抛出异常; ③睡眠结束的线程未必立刻执行; ④TimeUnit的sleep比Thread的sleep具有更哈ode可读性

yield(本意是让的意思,cpu让给其他线程): 从running进入runnable

应用(sleep/yield)防止while(ture)空转浪费cpu,可用sleep/yield来让出cpu的使用权给其他程序

线程优先级:提示任务调度器优先调度该线程,仅做提示;  t1.setPriority()

t1.jion: 等待线程运行结束(可以理解成t1加入主线程,并发执行)

应用(join,同步应用/限时同步): 等待多个线程的结果(调用方,调用多个其他线程的join方法)

interrupt(打断阻塞状态线程, 打断正在运行的线程)方法:

打断sleep,wait,join的线程(被打断后 打断标记清空,为假, t1.isInterrupted)

打断正常运行线程,不会直接打断,而是可以根据打断标记(Thread.currentThread().isInterruptedException()获取打断标记)决定是继续还是打断线程.

打断park线程,不会清空打断状态  park被打断之后 再调用park失效.(可以通过Thread.interrupted()方法,返回打断标记为真并重置打断标记为false,帮助后续park再次暂停)

​​​​​​​主线程和守护线程

默认情况下,java虚拟机需要等待所有线程结束,才会结束. 有一种特殊的线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没执行完,也会强制结束.  通过启动前(t1.start())调用t1.setDaemon(),可将线程设置成守护线程

垃圾回收线程,也是一种守护线程

​​​​​​​线程状态

从操作系统角度看,存在五种状态:

[初始状态] 仅语言层面创建了线程对象, 还未与操作系统线程关联

[可运行状态] (就绪状态) 已创建线程对象(也与操作系统关联了),可以由cpu调度执行

[运行状态] 获取了cpu时间片后 线程运行中的状态.  当时间片用完了就会切换至可运行状态,导致线程上下文切换

[阻塞状态] 调用了阻塞api后, 线程让出cup使用权, 任务调度器不会考虑将cpu的时间片分配给阻塞状态的线程,这也会导致线程的上下文切换. 结束后会进入可运行状态,并不是可以立刻进入运行状态.

[终止状态] 线程代码运行完了,生命周期结束,不会转换成其他状态

从Java API层面来看,存在六种状态:

NEW: 还未调用start()方法, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值