但是我们需要注意:
- Context Switch 频繁发生会影响性能
线程方法总述我们首先给出线程的全部方法一览:
方法功能说明public void start()启动一个新线程;Java虚拟机调用此线程的run方法start 方法只是让线程进入就绪 , 里面代码不一定立刻 运行(CPU 的时间片还没分给它) 。每个线程对象的 start方法只能调用一次,如果调用了多次会出现 IllegalThreadStateExceptionpublic void run()线程启动后调用该方法如果在构造 Thread 对象时传递了 Runnable 参数,则 线程启动后会调用 Runnable 中的 run 方法,否则默 认不执行任何操作 。但可以创建 Thread 的子类对象,来覆盖默认行为public void setName(String name)给当前线程取名字public void getName()获取当前线程的名字 。线程存在默认名称:子线程是Thread-索引,主线程是mainpublic 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 10java中规定线程优先级是1~10 的整数 , 较大的优先级 能提高该线程被 CPU 调度的机率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)将此线程标记为守护线程或用户线程public long getId()获取线程长整型 的 idid 唯一public state getState()获取线程状态Java 中线程状态是用 6 个 enum 表示,分别为: NEW, RUNNABLE, BLOCKED, WAITING,TIMED_WAITING, TERMINATEDpublic boolean isInterrupted()判断是否被打 断不会清除 打断标记start与run我们首先来介绍线程的两个相似的启动方法:
// 首先我们采用start:start方法是启动该线程,线程开始运行public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug(Thread.currentThread().getName());FileReader.read(Constants.MP4_FULL_PATH);}};t1.start();log.debug("do other things ...");}// 然后我们直接使用run方法:run方法是调用该线程的run方法,实际是main线程在运行t1线程的run方法public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug(Thread.currentThread().getName());FileReader.read(Constants.MP4_FULL_PATH);}};t1.run();log.debug("do other things ...");}
同时我们可以通过查看线程状态来判断start和run的区别:// 这里我们仅对start判断public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("running...");}};System.out.println(t1.getState());t1.start();System.out.println(t1.getState());}// 我们可以注意到main状态从就绪状态切换为RunnableNEWRUNNABLE03:45:12.255 c.Test5 [t1] - running...
所以我们给出小结:- 直接调用 run 是在主线程中执行了 run,没有启动新的线程
- 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码
- 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
- 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
- 睡眠结束后的线程未必会立刻得到执行
- 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性。其底层还是sleep方法
- 在循环访问锁的过程中,可以加入sleep让线程阻塞时间 , 防止大量占用cpu资源
- 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程;具体的实现依赖于操作系统的任务调度器
- 加入当前线程中只有这一个方法,那么停止该方法执行后仍旧执行该方法
/*sleep状态转换:我们运行下面代码后可以看到其t1状态从就绪状态到Runnable到Timed Waiting*/public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("running...");try {Thread.sleep(2000);} catch (InterruptedException e) {log.debug("wake up...");e.printStackTrace();}}};System.out.println(t1.getState());t1.start();System.out.println(t1.getState());Thread.sleep(2000);System.out.println(t1.getState());}/*sleep打断睡眠线程,抛出异常:注意当睡眠时抛出异常后该程序的打断状态为false*/ public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("enter sleep...");try {Thread.sleep(2000);} catch (InterruptedException e) {log.debug("wake up...");e.printStackTrace();}}};t1.start();Thread.sleep(1000);log.debug("interrupt...");t1.interrupt();}// 输出结果为:03:47:18.141 c.Test7 [t1] - enter sleep...03:47:19.132 c.Test7 [main] - interrupt...03:47:19.132 c.Test7 [t1] - wake up...java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at cn.itcast.test.Test7$1.run(Test7.java:14)/*sleep采用TimeUnit的方法更具有代码可读性*/@Slf4j(topic = "c.Test8")public class Test8 {public static void main(String[] args) throws InterruptedException {log.debug("enter");TimeUnit.SECONDS.sleep(1);log.debug("end");//Thread.sleep(1000);}}/*yield简单测试:我们需要在Linux虚拟机中使用单核cpu来处理该代码,下面我们同时使用一个cpu处理两个进程*/@Slf4j(topic = "c.TestYield")public class TestYield {public static void main(String[] args) {Runnable task1 = () -> {int count = 0;for (;;) {System.out.println("---->1 " + count++);}};Runnable task2 = () -> {int count = 0;for (;;) {Thread.yield();System.out.println("---->2 " + count++);}};Thread t1 = new Thread(task1, "t1");Thread t2 = new Thread(task2, "t2");t1.start();t2.start();}}// 我们会发现task1的count数更多,因为轮到task2时,它会调用yield可能会导致当前线程停止从而去运行另一个线程---->1 119199---->2 101074
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Seata 1.5.2 源码学习
- 第4版 高性能MySQL 第一章 MySQL架构 读书笔记
- Helm干货!速度围观!
- .NET 源码学习 [数据结构-线性表1.2] 链表与 LinkedList<T>
- MPC:百万富翁问题
- PGL Paddle Graph Learning 关于图计算&图学习的基础知识概览:前置知识点学习
- JVM学习笔记——内存模型篇
- Linux学习环境搭建流程
- Archlinux + Dwm 配置流程
- 关于入门深度学习mnist数据集前向计算的记录