我们知道我们打开个程序(或者说运行一款软件)其实也就是创建了一个进程,只不过程序是静态指令的集合,而进程是正在系统中运行的指令集合,进程是系统进行资源分配与调度的一个独立单位。进程具有独立性,动态性,并发性。现在的操作系统都支持并发,但在具体实现的细节上,根据硬件和操作系统的不同存在不同的策略,比较常用的方式有:共用式的多任务操作策略,抢占式的多任务策略。
线程扩展了进程的概念,线程是进程的执行单元,线程在进程中也是独立存在的,是一种并发的执行流,当进程被初始化之后,主线程就被创建出来了。对于绝大多数程序来说只有一个主线程,我们可以同时创建多条线程顺序执行流也就是线程。也就是说线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈,自己的计数器,自己的局部变量等。但他们不在拥有系统资源,而是与其他线程之间共享该进程所拥有的所有的资源。线程用来完成一定的任务,可与其他线程之间共享父进程中的共享变量及部分环境,相互之间协同来完成进程所要完成的工作。
简单来说:一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少包含一个线程。
线程的创建和启动:
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例,每条线程的任务就是完成一定的任务,实际就是执行一段程序流,而java使用run方法来封装这段程序流。接下来介绍两种创建线程的方法。
第一种继承Thread类来创建线程类:
1、定义Thread类的子类,并重写Thread类的run方法,这个run方法的方法体就代表了线程需要完成的任务,就是线程执行体了。
2、创建Thread类子类的实例,也就是创建线程对象。
3、用线程的start方法来启动线程。
下面是一个具体的例子:
/** * */ package cn.wan; /** * @author Administrator * */ public class TestHread extends Thread{ private int i; public void run() { for(;i<20;i++) { System.out.println(getName()+""+i); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub for(int i = 0;i<100;i++) { System.out.println(Thread.currentThread().getName()+""+i); if(i== 20) { new TestHread().start(); System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAA"); new TestHread().start(); } } } }
当Java程序运行时,至少会创建一个线程,那就是主线程,主线程的线程执行体不是由run方法来确定的,而是由main方法来确定的。main方法的方法体代表主线程的线程执行体。
第二种实现Runnable接口创建线程类
1、定义Runnable接口的实现类并重写该接口的run方法,该run方法的方法体同样是该线程的线程执行体。
2、创建Runnable实现类的实例,并以此实例来作为Thread类的target来创建Thread对象。这个Thread类的实例才是真正的线程对象。
// 创建Runnable接口实现的对象,SecondThread类实现了这个接口, SecondThread st = new SecondThread(); Thread th = new Thread(st);
下面是一个具体有的例子:
package cn.wan; public class SecondThread implements Runnable{ private int i; @Override /** * run方法同样是线程的执行体 */ public void run() { // TODO Auto-generated method stub for(;i<100;i++) { // 当线程类实现Runnable接口时 // 如果想获得当前线程,只能用Tread.currentThread()方法 System.out.println(Thread.currentThread().getName()+""+i); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub for(int i = 0;i<100;i++) { System.out.println(Thread.currentThread().getName()+""+i); if(i== 20) { SecondThread st = new SecondThread(); // 通过new Thread(target,name)方法创建新线程 new Thread(st,"first one").start(); System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAA"); new Thread(st,"second one").start(); } } } }
第一种和第二种方法主要差别在:
第一种
劣势:因为线程类已经继承了Thread类,所以不能再继续继承父类。
优势:编写简单,如果需要访问当前进程只需使用this关键字即可。无需使用Thread.currentThread方法。
第二种
劣势:编写复杂,如果需要访问当前线程需要使用Thread.currentThread方法。
优势:线程类只是继承了Runnable接口,还可以继承其他类。同时多线程可以同时共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况。