一、什么是线程
线程是一个程序内部的顺序控制流。
线程和进程
1.进程:每个进程都有独立的代码和数据空间,进程切换开销大。
2.线程:轻量的进程,同一个线程共享代码和数据空间,每个线程有独立运行的栈和程序计数器(PC),线程切换的开销小。
3.在操作系统中能同时运行多个任务(程序)。
4.在同一应用程序有多个顺序流同时执行。
问题:对于单核的CPU,处理多个任务时。并不会同时真正的运两个以上的程序。那么它是怎样做到处理多任务的呢?
解答:实际上是操作系统负责对处理器就是CPU等资源进行分配组织和管理。实际上每一时刻只能做一件事,或者运行某一个程序。由于在操作系统的管理下,CPU的处理功能被以非常小的时间间隔进行划分、进行交替,每一个小的时间间隔我们称为时间片。当时间片到期之后将去执行下一个程序。由于交替的速度非常的快,这样就给人一种同时运行多个应用程序或者同时做多件事的一种感觉。这种情况我们称为并发执行。也就是假的,模拟的,通过快速的交替,表现成在同时做多件事。
并行执行才是真正意义上的同一时刻做多个事情,同一个瞬间运行不同的应用程序。这样就要求有多个CPU。支持程序并发运行的操作系统我们称为多任务的操作系统或者说是多进程的操作系统。
并发性的工作原理还可以应用在更高的层面上,我们可以在一个应用程序的内部,把它要完成的任务分解为多个更小的子任务以多条齐头并进的线索来并发的执行,这种就称为线程或多线程。
二、线程的概念模型
Java语言实现或支持多线程的工作方式。
一个线程必须具备以下三方面的要素才能正常的工作。
1.虚拟的CPU,由java.lang.Thread类封装和虚拟。
2.CPU所执行的代码,传递给Thread类的对象。
3.CPU所处理的数据,传递给Thread类的对象。
三、创建线程
第一种方式:使用Runnable接口创建线程
1.Java的线程是通过java.lang.Thread类来实现。
2.每个线程都是通过某个特定的Thread对象所对应的run()方法来完成其操作。方法run()称为线程体。
例1:
public class Thread1{
public static void main(String[] args){
Runner1 r=new Runner1();//2.创建实现Runnable接口的对象
Thread t=new Thread(r); //3.创建一个Thread类的对象
t.start(); //4.启动线程
}
}
class Runner1 implements Runnable{//1.Runner1实现Runnable接口
public void run(){
for(int i=1;i<20;i++){
System.out.println(i);
}
}
}
程序运行的结果是输出1到19个数字。与在main()方法中直接写for循环是一样的效果。
但实现的原理不一样。
使用线程输出的有两个线程(main()主线程和t子线程),不使用只有一个线程。
创建线程的三个步骤
1.定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
2.创建Runnable接口实现类的对象。
3.创建一个Thread类的对象,需要封装前面Runnable接口实现类的对象。(接口可以实现多继承)
4.调用Thread对象的start()方法,启动线程
第二种方式:直接继承Thread类创建对象
例2:
public class Thread2{
public static void main(String[] args){
Thread t=new Runner2();
t.start();
}
}
class Runner2 extends Thread{
public void run(){
for(int i=1;i<20;i++){
String s=Thread.currentThread().getName();
System.out.println(s+":"+i);
}
}
}
1.首先定义一个类去继承Thread父类,此时Runner2类并没有直接的实现Runnable接口,但其实Thread类在JDK中已经实现了Runnable接口。这样就Runner2类间接的实现了Runnable接口。重写父类中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
2.直接创建一个Runner2类的对象,也可以利用多态性,变量t声明为父类的类型。
3.线程t启动,隐含的调用run()方法。
比较两种方式:
a.使用Runnable接口创建线程
1.可以将CPU,代码和数据分开,形成清晰的模型
2.线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法
3.有利于保持程序的设计风格一致
b.直接继承Thread类创建对象
1.Thread子类无法再从其它类继承(java语言的单继承)。
2.编写简单,run()方法的当前对象就是线程对象,可直接操作。