1. 首页
  2. IT资讯

那些基础的线程知识,你都懂了吗?| CSDN 博文精选

“u003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRbiRsmjFrZY4rp” img_width=”640″ img_height=”100″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002FRZVVSbFDJ4hK4e” img_width=”1080″ img_height=”724″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003E作者 | LieBrotheru003Cu002Fpu003Eu003Cpu003E责编 | 屠敏u003Cu002Fpu003Eu003Cpu003E出品 | CSDN 博客u003Cu002Fpu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRT4Gwk56bt5iOJ” img_width=”340″ img_height=”57″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003Eu003Cstrongu003E什么是线程?u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E试想一下没有线程的程序是怎么样的?百度网盘在上传文件时就无法下载文件了,得等文件上传完成后才能下载文件。这个我们现在看起来很反人性,因为我们习惯了一个程序同时可以进行运行多个功能,而这些都是线程的功劳。u003Cu002Fpu003Eu003Cpu003E之前的文章 、进程知多少 中讲到,为了实现多个程序并行执行,引入了进程概念。现在引入线程是为了让一个程序能够并发执行。u003Cu002Fpu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRT7S2kzFTfre26″ img_width=”340″ img_height=”57″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003Eu003Cstrongu003E线程的组成u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Culu003Eu003Cliu003Eu003Cpu003E线程ID:线程标识符。u003Cu002Fpu003Eu003Cu002Fliu003Eu003Cliu003Eu003Cpu003E当前指令指针(PC):指向要执行的指令。u003Cu002Fpu003Eu003Cu002Fliu003Eu003Cliu003Eu003Cpu003E寄存器集合:存储单元寄存器的集合。u003Cu002Fpu003Eu003Cu002Fliu003Eu003Cliu003Eu003Cpu003E堆栈:暂时存放数据和地址,一般用来保护断点和现场。u003Cu002Fpu003Eu003Cu002Fliu003Eu003Cu002Fulu003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002FRTJXJ1kBqzfCnu” img_width=”340″ img_height=”57″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003Eu003Cstrongu003E线程与进程区别u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E线程和进程之间的区别,我觉得可以用这个例子来看出两者的不同,进程就是一栋房子,房子住着 3 个人,线程就是住在房子里的人。进程是一个独立的个体,有自己的资源,线程是在进程里的,多个线程共享着进程的资源。u003Cu002Fpu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRTJXJ7YR5xGDl” img_width=”340″ img_height=”57″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003Eu003Cstrongu003E线程状态u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E我们看到 Java 源代码里面,线程状态的枚举有如下 6 个。u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Epublic enum State {u003Cbru003Eu003Cbru003Eu002Fu002F新建状态u003Cbru003ENEW,u003Cbru003Eu003Cbru003Eu002Fu002F运行状态u003Cbru003ERUNNABLE,u003Cbru003Eu003Cbru003Eu002Fu002F阻塞状态u003Cbru003EBLOCKED,u003Cbru003Eu003Cbru003Eu002Fu002F等待状态u003Cbru003EWAITING,u003Cbru003Eu003Cbru003Eu002Fu002F等待状态(区别在于这个有等待的时间)u003Cbru003ETIMED_WAITING,u003Cbru003Eu003Cbru003Eu002Fu002F终止状态u003Cbru003ETERMINATED;u003Cbru003E}u003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E下面给这 6 个状态u003Ci class=”chrome-extension-mutihighlight chrome-extension-mutihighlight-style-5″u003E一一u003Cu002Fiu003E做下解释。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003ENEW:u003Cu002Fstrongu003E新建状态。在创建完 Thread ,还没执行 start 之前,线程的状态一直是 NEW。可以说这个时候还没有真正的一个线程映射着,只是一个对象。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003ERUNNABLE:u003Cu002Fstrongu003E运行状态。线程对象调用 start 之后,就进入 RUNNABLE 状态,该状态说明在 JVM 中有一个真实的线程存在。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003EBLOCKED:u003Cu002Fstrongu003E阻塞状态。线程在等待锁的释放,也就是等待获取 monitor 锁。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003EWAITING:u003Cu002Fstrongu003E等待状态。线程在这个状态的时候,不会被分配 CPU,而且需要被显示地唤醒,否则会一直等待下去。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003ETIMED_WAITING:u003Cu002Fstrongu003E超时等待状态。这个状态的线程也一样不会被分配 CPU,但是它不会无限等待下去,有时间限制,时间一到就停止等待。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003ETERMINATED:u003Cu002Fstrongu003E终止状态。线程执行完成结束,但不代表这个对象已经没有了,对象可能还是存在的,只是线程不存在了。u003Cu002Fpu003Eu003Cpu003E线程既然有这么多个状态,那肯定就有状态机,也就是在什么情况下 A 状态会变成 B 状态。下面就来简单描述一下。u003Cu002Fpu003Eu003Cpu003E结合下图,我们 new 出线程类的时候,就是 NEW 状态,调用 start 方法,就进入了 RUNNABLE 状态,这时如果触发等待,则进入了 WAITING 状态,如果触发超时等待,则进入 TIMED_WAITING 状态,当访问需要同步的资源时,则只有一个线程能访问,其他线程就进入 BLOCKED 状态,当线程执行完后,进入 TERMINATED 状态。u003Cu002Fpu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRcW0VEj8x2yXap” img_width=”1080″ img_height=”721″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003E其实在 JVM 中,线程是有 9 个状态,如下所示,有兴趣的同学可以深入了解一下。u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003EjavaClasses.hppu003Cbru003Eenum ThreadStatus {u003Cbru003ENEW = 0,u003Cbru003ERUNNABLE = JVMTI_THREAD_STATE_ALIVE + u002Fu002F runnable u002F runningu003Cbru003EJVMTI_THREAD_STATE_RUNNABLE,u003Cbru003ESLEEPING = JVMTI_THREAD_STATE_ALIVE + u002Fu002F Thread.sleepu003Cbru003EJVMTI_THREAD_STATE_WAITING +u003Cbru003EJVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +u003Cbru003EJVMTI_THREAD_STATE_SLEEPING,u003Cbru003EIN_OBJECT_WAIT = JVMTI_THREAD_STATE_ALIVE + u002Fu002F Object.waitu003Cbru003EJVMTI_THREAD_STATE_WAITING +u003Cbru003EJVMTI_THREAD_STATE_WAITING_INDEFINITELY +u003Cbru003EJVMTI_THREAD_STATE_IN_OBJECT_WAIT,u003Cbru003EIN_OBJECT_WAIT_TIMED = JVMTI_THREAD_STATE_ALIVE + u002Fu002F Object.wait(long)u003Cbru003EJVMTI_THREAD_STATE_WAITING +u003Cbru003EJVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +u003Cbru003EJVMTI_THREAD_STATE_IN_OBJECT_WAIT,u003Cbru003EPARKED = JVMTI_THREAD_STATE_ALIVE + u002Fu002F LockSupport.parku003Cbru003EJVMTI_THREAD_STATE_WAITING +u003Cbru003EJVMTI_THREAD_STATE_WAITING_INDEFINITELY +u003Cbru003EJVMTI_THREAD_STATE_PARKED,u003Cbru003EPARKED_TIMED = JVMTI_THREAD_STATE_ALIVE + u002Fu002F LockSupport.park(long)u003Cbru003EJVMTI_THREAD_STATE_WAITING +u003Cbru003EJVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +u003Cbru003EJVMTI_THREAD_STATE_PARKED,u003Cbru003EBLOCKED_ON_MONITOR_ENTER = JVMTI_THREAD_STATE_ALIVE + u002Fu002F (re-)entering a synchronization blocku003Cbru003EJVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER,u003Cbru003ETERMINATED = JVMTI_THREAD_STATE_TERMINATEDu003Cbru003E};u003Cbru003Eu003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRTJXJ7uHXU5GZc” img_width=”340″ img_height=”57″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003Eu003Cstrongu003EJava 线程实现u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E下面讲一讲在 Java 中如何创建一个线程。众所周知,实现 Java 线程有 2 种方式:继承 Thread 类和实现 Runnable 接口。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E继承 Thread 类u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E继承 Thread 类,重写 run 方法。u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Eclass MyThread extends Thread {u003Cbru003Eu003Cbru003E@Overrideu003Cbru003Epublic void run {u003Cbru003ESystem.out.println(“MyThread”);u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003E实现 Runnable 接口u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E实现 Runnable 接口,实现 run 方法。u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Eclass MyRunnable implements Runnable {u003Cbru003Eu003Cbru003Epublic void run {u003Cbru003ESystem.out.println(“MyRunnable”);u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E这 2 种线程的启动方式也不一样。MyThread 是一个线程类,所以可以直接 new 出一个对象出来,接着调用 start 方法来启动线程;而 MyRunnable 只是一个普通的类,需要 new 出线程基类 Thread 对象,将 MyRunnable 对象传进去。u003Cu002Fpu003Eu003Cpu003E下面是启动线程的方式。u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Epublic class ThreadImpl {u003Cbru003Eu003Cbru003Epublic static void main(String[] args) {u003Cbru003EMyThread myThread = new MyThread;u003Cbru003EThread myRunnable = new Thread(new MyRunnable);u003Cbru003ESystem.out.println(“main Thread begin”);u003Cbru003EmyThread.start;u003Cbru003EmyRunnable.start;u003Cbru003ESystem.out.println(“main Thread end”);u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E打印结果如下:u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Emain Thread beginu003Cbru003Emain Thread endu003Cbru003EMyThreadu003Cbru003EMyRunnableu003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E看这结果,不像咱们之前的串行执行依次打印,主线程不会等待子线程执行完。u003Cu002Fpu003Eu003Cpu003E敲重点:不能直接调用 run,直接调用 run 不会创建线程,而是主线程直接执行 run 的内容,相当于执行普通函数。这时就是串行执行的。看下面代码。u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Epublic class ThreadImpl {u003Cbru003Eu003Cbru003Epublic static void main(String[] args) {u003Cbru003EMyThread myThread = new MyThread;u003Cbru003EThread myRunnable = new Thread(new MyRunnable);u003Cbru003ESystem.out.println(“main Thread begin”);u003Cbru003EmyThread.run;u003Cbru003EmyRunnable.run;u003Cbru003ESystem.out.println(“main Thread end”);u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E打印结果:u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Emain Thread beginu003Cbru003EMyThreadu003Cbru003EMyRunnableu003Cbru003Emain Thread endu003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E从结果看出只是串行的,但看不出没有线程,我们看下面例子来验证直接调用 run 方法没有创建新的线程,使用 VisualVM 工具来观察线程情况。u003Cu002Fpu003Eu003Cpu003E我们对代码做一下修改,加上 Thread.sleep(1000000) 让它睡眠一段时间,这样方便用工具查看线程情况。u003Cu002Fpu003Eu003Cpu003E调用 run 的代码:u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Epublic class ThreadImpl {u003Cbru003Eu003Cbru003Epublic static void main(String[] args) {u003Cbru003EMyThread myThread = new MyThread;u003Cbru003EmyThread.setName(“MyThread”);u003Cbru003EThread myRunnable = new Thread(new MyRunnable);u003Cbru003EmyRunnable.setName(“MyRunnable”);u003Cbru003ESystem.out.println(“main Thread begin”);u003Cbru003EmyThread.run;u003Cbru003EmyRunnable.run;u003Cbru003ESystem.out.println(“main Thread end”);u003Cbru003Etry {u003Cbru003EThread.sleep(1000000);u003Cbru003E} catch (InterruptedException e) {u003Cbru003Ee.printStackTrace;u003Cbru003E}u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cbru003Eu003Cbru003Eclass MyThread extends Thread {u003Cbru003Eu003Cbru003E@Overrideu003Cbru003Epublic void run {u003Cbru003ESystem.out.println(“MyThread”);u003Cbru003Etry {u003Cbru003EThread.sleep(1000000);u003Cbru003E} catch (InterruptedException e) {u003Cbru003Ee.printStackTrace;u003Cbru003E}u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cbru003Eu003Cbru003Eclass MyRunnable implements Runnable {u003Cbru003Eu003Cbru003Epublic void run {u003Cbru003ESystem.out.println(“MyRunnable”);u003Cbru003Etry {u003Cbru003EThread.sleep(1000000);u003Cbru003E} catch (InterruptedException e) {u003Cbru003Ee.printStackTrace;u003Cbru003E}u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E运行结果:u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Emain Thread beginu003Cbru003EMyThreadu003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRcW0VEuD9hMW25″ img_width=”1080″ img_height=”202″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003E只打印出 2 句日志,观察线程时也只看到 main 线程,没有看到 MyThread 和 MyRunnable 线程,印证了上面咱们说的:直接调用 run 方法,没有创建线程。u003Cu002Fpu003Eu003Cpu003E下面我们来看看有u003Cu002Fpu003Eu003Cpu003E调用 start 的代码:u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Epublic class ThreadImpl {u003Cbru003Eu003Cbru003Epublic static void main(String[] args) {u003Cbru003EMyThread myThread = new MyThread;u003Cbru003EmyThread.setName(“MyThread”);u003Cbru003EThread myRunnable = new Thread(new MyRunnable);u003Cbru003EmyRunnable.setName(“MyRunnable”);u003Cbru003ESystem.out.println(“main Thread begin”);u003Cbru003EmyThread.start;u003Cbru003EmyRunnable.start;u003Cbru003ESystem.out.println(“main Thread end”);u003Cbru003Etry {u003Cbru003EThread.sleep(1000000);u003Cbru003E} catch (InterruptedException e) {u003Cbru003Ee.printStackTrace;u003Cbru003E}u003Cbru003E}u003Cbru003Eu003Cbru003E}u003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cpu003E运行结果:u003Cu002Fpu003Eu003Cpreu003Eu003Ccodeu003Emain Thread beginu003Cbru003Emain Thread endu003Cbru003EMyThreadu003Cbru003EMyRunnableu003Cu002Fcodeu003Eu003Cu002Fpreu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRcW0VF5GKXZYNe” img_width=”1080″ img_height=”200″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003E所有日志都打印出来了,并且通过 VisualVM 工具可以看到 MyThread 和 MyRunnable 线程。看到了这个结果,切记创建线程要调用 start 方法。u003Cu002Fpu003Eu003Cpu003E声明:本文为 CSDN 博主「LieBrother」的原创文章,版权归作者所有。u003Cu002Fpu003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fpgc-imageu002FRVLPVid4kflaU5″ img_width=”108″ img_height=”98″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fpgc-imageu002FRVLPViq7YdUeev” img_width=”197″ img_height=”50″ alt=”那些基础的线程知识,你都懂了吗?| CSDN 博文精选” inline=”0″u003Eu003Cpu003E成就一亿技术人u003Cu002Fpu003Eu003Cpu003E成为技术人交流和成长的家园u003Cu002Fpu003E”

原文始发于:那些基础的线程知识,你都懂了吗?| CSDN 博文精选

主题测试文章,只做测试使用。发布者:熱鬧獨處,转转请注明出处:http://www.cxybcw.com/15101.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code