多线程高并发问题(【多线程与高并发】- 线程基础与状态)
线程基础与状态
?生命不息 ,写作不止
? 继续踏上学习之路 ,学之分享笔记
? 总有一天我也能像各位大佬一样
? 一个有梦有戏的人 @怒放吧德德
?分享学习心得,欢迎指正 ,大家一起学习成长!前言
好久没坚持学习了 ,所以 ,这次要好好下定决心学习 。多线程与高并发不是一天两天就能弄懂的 ,需要不断的学习 、实践 ,本次笔者将最近学习的内容知识记录下来 。多线程也是一项比较重要的内容 ,虽然CRUD不太会接触到 ,但是 ,在一些相关场景可能会有某些问题是由于线程导致的。
线程的概念
要了解线程的概念 ,就需要知道什么是进程 。简单理解就是一个进程中包含了许多个线程 。现在就简单介绍,后续若是有对操作系统进行研究的话会慢慢介绍 ,具体关于线程进程的内容可以去看看王道的操作系统 ,里面讲述得特别清楚 。
什么是进程?
是系统进行资源分配的基本单位,是操作系统结构的基础 ,进程是线程的容器 。程序是指令 、数据及其组织形式的描述 ,进程是程序的实体 。
什么是线程?
所谓线程就是操作系统(OS)能够进行运算调度的最小单位,是一个基本的CPU执行单元 ,也是执行程序流的最小单元 。能够提高OS的并发性能 ,减小程序在并发执行时所付出的时空开销 。线程是进程的一个实体 ,是被系统独立调度和分派的基本单位 。线程本身是不拥有系统资源的 ,但是它能够使用同属进程的其他线程共享进程所拥有的全部资源 。
在Java线程中是怎样的呢?
在Java中 ,最常见得就是继承Thread类或者实现Runnable接口 ,再通过run或者start方法去执行线程。
如以下代码 ,这是一段很简单得代码块 ,通过继承Thread类 ,重写run方法来创建线程,并且通过run和start来运行 。 public class Thread_demo01 { private static class Thread1 extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { try { Thread.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("Thread1-" + i); } } } public static void main(String[] args) { new Thread1().run(); // 顺序执行 // new Thread1().start(); // 线程同时执行 for (int i = 0; i < 5; i++) { try { Thread.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("main"); } } }这两种不同得启动方式 ,出现得现象也是不同的 。
使用run方法启动线程
使用start方法启动线程
关于这两种方式启动线程可以看一下下面的流程图。
run方法是会让线程T1先执行完毕之后 ,再继续执行主线程,而start方法他是同时执行两个线程 。Java线程的Sleep、Yield 、Join方法
1 、sleep方法
sleep()需要提供一个时间参数(毫秒) ,会使得线程在一定的时间内被暂停执行 ,在sleep的过程中,线程是不会释放锁的 ,只会进入阻塞状态 ,让出cpu给其他线程去执行 。如下代码演示 ,此处不做锁的探究。
public class T3_Thread_Sleep { public static void main(String[] args) { Thread t1 = new Thread(new Thread1()); Thread t2 = new Thread(new Thread2()); t1.start(); t2.start(); } static class Thread1 implements Runnable { @Override public void run() { System.out.println("T1 is running"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("T1 is end"); } } static class Thread2 implements Runnable { @Override public void run() { System.out.println("T2 is running"); try { Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("T2 is end"); } } }运行之后在T1线程休眠的时候会让出cpu资源给T2线程 ,T1线程会睡眠1秒 ,T2睡眠2秒 ,最终结果如图
2 、Yield方法
yield()与sleep()都是让线程暂停执行 ,也是不会释放锁资源 。但是yield并不是让进程进入阻塞态 ,而是回到就绪态 ,等待重新获取CPU资源 。此时,其他的线程有机会获得cpu资源 ,也有可能在yield方法进入就绪态后立马变成执行态 。如以下代码 ,同样不考虑锁的问题 。
public class T4_Thread_Yield { static class Thread1 implements Runnable { @Override public void run() { System.out.println("T1 is running"); Thread.yield(); System.out.println("T1 is end"); } } static class Thread2 implements Runnable { @Override public void run() { System.out.println("T2 is running"); System.out.println("T2 is end"); } } public static void main(String[] args) { Thread t1 = new Thread(new Thread1()); Thread t2 = new Thread(new Thread2()); t1.start(); t2.start(); } }经过不同的测试,结果都是不同的 。
3 、Join方法
join()方法是暂停当前线程 ,调用执行另一个线程 ,等待join的线程执行完毕后才能够继续执行当前线程 。如以下例子,T1,T2同时开始 ,在T2线程中join了T1 ,就会导致T1要先执行完毕之后 ,才会去执行T2 。
public class T5_Thread_Join { public static void main(String[] args) { Thread T1 = new Thread(() -> { System.out.println("T1开始"); for (int i = 0; i < 5; i++) { System.out.println("线程T1执行中: " + i); } System.out.println("T1结束"); }); Thread T2 = new Thread(() -> { System.out.println("T2开始"); for (int i = 0; i < 5; i++) { System.out.println("线程T2执行中: " + i); if (i == 3) { try { T1.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } System.out.println("T2结束"); }); T1.start(); T2.start(); } }结果如下 ,不管怎么测试 ,都会是T2最后执行结束 。
Java的线程状态
线程具有最基本的三态(就绪 、运行 、阻塞) 。线程与进程一样 ,各线程之间也存着共享资源和互相合作的制约关系 ,致使线程运行时具有间断性。接下来看一下如图 ,这是五种状态的转化 。
线程的不同状态
在Java线程中有6中状态 ,从线程的创建到线程的终止 。线程创建为NEW创建态,通过start启动线程 ,线程内部会从就绪态转成运行态 ,在Java线程中统称为“运行态 ”,线程由于被挂起 、调用yeild等方法能够使线程从运行态转成就绪态 ,也能够通过线程的其他方法或者锁阻塞线程 ,直到时间结束或者是获得锁等,从而回到RUNABLE状态。
初始(NEW):新创建了一个线程对象 ,但还没有调用start()方法 。 运行(RUNNABLE):Java线程中将就绪(Ready)和运行中(Running)两种状态笼统的称为“运行 ” 。线程对象创建后 ,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中 ,等待被线程调度选中 ,获取CPU的使用权 ,此时处于就绪状态(Ready) 。就绪状态的线程在获得CPU时间片后变为运行中状态(Running) 。 阻塞(BLOCKED):表示线程阻塞于锁 。 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断) 。 超时等待(TIMED_WAITING):该状态不同于WAITING ,它可以在指定的时间后自行返回 。 终止(TERMINATED):表示该线程已经执行完毕 。Java线程的状态转化
如线程状态转换图 ,以下就是Java线程状态的转换流程 。线程可以通过实现Runnable接口或者继承Threa类 ,然后去实例化Java的线程对象 。在线程被执行之前都是属于创建态(NEW) ,在调用start方法后,线程就会转成RUNABLE状态 ,在RUNABLE中 ,当线程处于就绪态(Ready)的时候,经过调度分配了cpu资源 ,这时转成了运行态 ,当线程被挂起 、线程执行了yield,线程将会退回就绪态 。在运行态(RUNABLE) ,也会通过一些处理而被阻塞或者等待。终止状态(TERMINATED)是线程执行完毕退出 ,此时 ,终止态的线程不会直接转成创建态 。
Java线程状态代码
Java中线程的状态都是在java.lang.Thread.State
的枚举类中 。
可以看一下以下枚举代码 ,分别为(NEW 、RUNNABLE、BLOCKED 、WAITING 、TIMED_WAITING、TERMINATED)六种。 public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; }接下来看一下演示代码
public class T6_Thread_State { static class Thread1 extends Thread { @Override public void run() { System.out.println("run - 当前线程的状态: " + this.getState()); for (int i = 0; i < 5; i++) { try { System.out.println("sleep前 - 当前线程的状态: " + this.getState()); Thread.sleep(1000); System.out.println("sleep后 - 当前线程的状态: " + this.getState()); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public static void main(String[] args) throws InterruptedException { Thread1 t1 = new Thread1(); System.out.println("main - 当前线程的状态: " + t1.getState()); t1.start(); System.out.println("join前 - 当前线程的状态: " + t1.getState()); t1.join(); System.out.println("join后 - 当前线程的状态: " + t1.getState()); } }运行结果 ,可以只管看到线程在运行过程种的状态切换 。
博文推荐
这里推荐给各位一篇很不错的博客文章 ,是针对Java线程的状态转换的详细介绍
Java线程的6种状态及切换(透彻讲解)_潘建南的博客-CSDN博客_线程的5种状态
线程池 waiting on condition_Java线程生命周期与状态切换_有所不知的博客-CSDN博客
?创作不易 ,如有错误请指正 ,感谢观看!记得点赞哦!?
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!