在编程中,很多时候,我们需要计算机同时处理多件事情,例如说,就拿我相对最熟悉的web服务来说,web程序必须支持多用户访问,要不然如果你的用户只能支持一个用户在线访问,其他用户只能以排队的形式等待,估计你的网站没有谁愿意使用。
多线程提供给我们这样一种手段:同个时间内,我们可以运行多个程序路径,当然,同一个时间段这个说法只是说在我们人这个尺度来说是同时的,cpu其实是串行交替执行各个线程的代码路径的(单核cpu,多核的话估计是正真的并行)。多线程使得我们可以充分利用cpu的资源,毕竟cpu的运算速度太快了。下面对前段时间对多线程的学习收获进行简单梳理和总结。
一、线程的概念
这个,不多说,只是为了内容完整性说说个人理解:代码执行上理解,没条线程代表一个代码执行路径;操作系统上面说,线程是操作系统可以调度和分配资源的最小单位。下面简单看个丑图吧,它大概说明了线程是个什么东西:
所以,线程就是在原有程序的基础上,新开了一条(多条)执行路径,而且新开的路径和原来的路径会同时执行
二、java中的线程
1、如何实现多线程?
A、实现接口,废话不多说,上代码先:
//多线程实现方式一:实现接口 class ThreadTest1 implements Runnable{ public void run() { System.out.println("我是程执新执行路径的入口run方法"); } } //下面这个测试类展示了我们如何调用对应的实现了Runnable接口的类,从而实现多线程 public class ThreadStage { public static void main(String[] args) { //题外话:main也是条线程!它是java程序执行的入口 Thread thread = new Thread(new ThreadTest1()); thread.start();//start线程的开始执行的标记方法(当然,start方法执行了并不代表线程就执行了,后面具体说这个问题) System.out.print("我是main方法的执行路径,其实我也只是一条线程"); } }
OK,这样就实现了程序的多线程,是不是炒鸡简单?在上面中,run方法就是相当于新路径的执行入口,所有该路径的执行代码都从这里执行开始,这里有个误区:新开一条线程是调用Thread的start方法,不是直接调用run方法!如果直接调用run方法,只是简单地在原有路径中串行执行run方法的代码,不会新开一条执行路径。
B、另外一种方法就是继承Thread类,上代码:
//多线程实现方法二 class ThreadTest2 extends Thread{ //重写run方法即可 public void run(){ System.out.println("sleep"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("我是新线程,是通过继承thread实现的新代码执行路径"); } } //下面是对ThreadTest2中新开线程的示例 public class ThreadStage { public static void main(String[] args) { new ThreadTest2().start();//继承线程类的子类可以自己调用start方法直接开线程 System.out.println("我是main方法的执行路径,其实我也只是一条线程"); } }
废话就不多说了,代码也清楚展示了如何利用继承方法实现多线程了,要注意的还是上面那个问题:新开线程调用start方法,不能调用run方法!
C、两种方法,用哪种?
一般来说,用实现接口的方式,因为java不支持多继承。
三、线程的状态
1、线程状态转换。具体状态名不一 一列出来了,先用下面的丑图说明线程从出生到死亡的整个过程吧:
ok,图上面大概说明了线程状态了,当然,具体的状态解释下面会详细总结。
2、线程状态解释。
A、首先,new Thread动作发出后,代表内存中新建了一个Thread类的对象,在内存层面为线程做好线程执行的准备工作;
B、然后,调用start方法,这是,相当于告诉操作系统:该线程的所有准备工作已经完成,操作系统你可以来调度我啦,所以,start并不代表线程开始运行,它只是出于一个准备完成随时可以被操作系统调度这样一个状态而已;
C、当在执行中遇到sleep,wait或者阻塞情形时,线程都会暂停执行,直到相应的条件满足或者其他线程再次激活线程,具体表现为:
sleep时,线程会在设定好的时间过去后,退出sleep执行状态,回到类似于start方法刚执行的状态,等待操作系统调度;
wait时,线程会处于等待状态,知道有某些线程调用一个叫做notifyAll(notify)方法时,线程等待状态才会退出,具体为什么要这个wait的状态后面的博客中会具体讨论;
阻塞时,是由于外界条件不满足程序的执行条件而使得程序处于等待状态,等待外界条件满足之后,线程才会退出该状态。
三种状态的具体区别大概如下:sleep保持程序锁定(不释放锁)而且自己控制什么时候退出该状态(通过时间设置);wait释放锁而且受其他线程控制才能再次进入执行状态(通过其他线程调用notify方法);阻塞不会释放锁而且只有满足条件时才会退出阻塞状态进入执行(例如申请的锁满足了),阻塞的状态改变依赖于外界条件或者说其他线程释放锁。
D、当判处异常时或者提前遇到run方法体中的return或者线程执行完毕时,线程进入消亡状态,等待GC。
线程基础篇1总结 大概这么多先,后面会再陆续整理线程的同步问题!