<span style="font-size: 14px; font-weight: bold; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------</span>
一、 进程和线程
1、 进程和线程的关系。
一般来说,我们运行一个应用程序的,就启动了一个进程,当然有些会启动多个进程。在进程中,有些程序流程块是可以乱序执行的,并且这个代码块可能同时被多次执行。实际上,这样的代码块就是线程体。线程是进程中乱序执行的代码流程,也就是执行路径。对我们初学者来说,可以简单的先理解为进程包含线程,一个进程至少要包含一个线程,进程的执行,也就是进程中的线程在执行。
2、多线程存在的意义。
多进程实现了多任务并发执行,程序的多线程实现了进程的并发执行。并发执行,也就是我们现在打开电脑可以在敲代码的同时使用音乐播放 器听歌。这里的并发执行不是说计算机的CPU在同时在执行两个程序,而是很多程序的线程在轮流执行(至于执行的顺序就要涉及到调度算法), 然而,因为计算机的运行速度很快,让我们感觉到是同时在运行的。举个例子,绳子绑着一个球,快速甩圈下,会看到一个圆圈,其实我们知道球 不可能是一个圆圈,只是速度太快了眼睛跟不上。同理,计算机的速度是非常快的,在我们没反应过来,它已经做了很多事情了。
二、 线程的两种创建方式:
1、继承Thread类
步骤:①、定义类一个继承Thread。
②、复写Thread中的run方法。
③、创建定义类的实例对象(相当于创建一个线程)。
④、用该对象调用线程的start方法(开启线程)。
代码:
//步骤①,创建线程A,它继承自Thread类 class ThreadA extends Thread { //步骤②,复写Thread类的run方法 public void run() { //线程执行代码.... } } class ThreadTest { public static void main(String[] args) { ThreadA a1 = new ThreadA();//步骤③,<span style="font-size: 14px; line-height: 26px;">创建Thread类的实例对象</span> <span style="white-space:pre"> </span>ThreadA a2 = new ThreadA(); a1.start();//开启一个线程 //步骤④,调用线程的start方法,开启线程 a2.start();//开启第二线程 //主线程中的的代码 } }
2、实现Runnable接口
步骤:①、定义一个类实现Runnable的接口。
②、覆盖Runnable接口中的run方法。
③、创建Runnable接口的子类的实例化对象。
④、通过Thread类创建线程对象,将Runnable接口的子类对象作为实参传递给Thread类的构造方法。
⑤、调用Thread类中start方法启动线程。
代码:
//步骤①,定义一个类实现Runnable的接口。 class ThreadA implements Runnable { //步骤②,覆盖Runnable接口中的run方法。 public void run() { //线程执行代码 } } class TicketDemo { public static void main(String[] args) { //步骤③,创建Runnable接口的子类的实例化对象。 ThreadA t = new ThreadA(); //步骤④,通过Thread类创建线程对象,将Runnable接口的子类对象作为实参传递给Thread类的构造方法。 Thread t1 = new Thread(t);//创建了一个线程 Thread t2 = new Thread(t);//创建了第二个线程 //步骤⑤,调用Thread类中start方法启动线程。 t1.start(); t2.start(); } }
三、 线程的两种创建方式的比较:
1、run方法
2、继承方式的缺点
3、接口实现的优点
①、适合多个相同的程序代码的线程去处理同一个资源
②、可以避免java中的单继承的限制
③、增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
四、线程的几种状态
注:①、线程调用sleep方法后会进入休眠状态,但是休眠结束后,并不能够马上执行,而是进入就绪状态,等待CPU资源。这里,提一点,sleep方法会发生异常,而且这里不能直接抛出异常,因为run方法复写了Runnable接口的方法,而接口中没有抛异常,所以sleep一抛异常就会出错,这里只能try、catch处理。
②、notify会唤醒进程池中的第一个线程,notifyAll会唤醒所用线程。
java程序启动后,主线程调用main方法,创建了很多子线程,这些子线程都处在创建状态,当这里线程调用start方法后,进入就绪状态,这时这些线程就有权利和主线程抢占CPU的资源(当然了,其他程序的线程也在抢CPU),谁抢到了CPU就可以执行一个时间片,所以我们在运行多线程时,可能会有多种不同的结果。