Java进程与线程
进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程。
多进程操作系统能同时运行多个进程(程序),由于CPU具备分时机制,所以每个进程都能循环获得自己的CPU时间片。
多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行,一个进程可能包含了多个同时执行的线程。
比如JVM就是一个操作系统,每当使用java命令执行一个类时,实际上都会启动一个jvm,每一个JVM实际上就是在操作系统中启动一个进程,java本身具备了垃圾回收机制,所以每个java运行时至少会启动两个线程,一个main线程,另外一个是垃圾回收机制。
Java中线程的实现
在Java中要想实现多线程代码有两种手段,一种是继承Thread类,另一种就是实现Runnable接口。
1.继承Thread类
//================================================= // File Name : Thread_demo //------------------------------------------------------------------------------ // Author : Common // 类名:Math // 属性: // 方法: class MyThread extends Thread{ private String name; public MyThread(String name) { //构造方法 super(); this.name = name; } public void run(){ //覆写Thread类中的run()方法 for (int i=0;i<10;i++){ System.out.println(name+"运行,i="+i); } } } //主类 //Function : Thread_demo public class Thread_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 MyThread mt1 = new MyThread("线程A "); MyThread mt2 = new MyThread("线程B "); mt1.start(); mt2.start(); } }
输出的结果可能是A线程和B线程交替进行,哪一个线程对象抢到了CPU资源,哪个线程就可以运行,在线程启动时虽然调用的是start()方法,但是实际上调用的却是run()方法的主体
如果一个类通过Thread类来实现,那么只能调用一次start()方法,如果调用多次,则将会抛出"IllegalThreadStateException"异常。
2.实现Runnable接口
仍然要依靠Thread类完成启动,在Thread类中提供了public Thread(Runnable target)和public Thread(Runnable target,String name)两个构造方法。
这两个构造方法都可以接受Runnable的子类实例对象。
//================================================= // File Name : Thread_demo //------------------------------------------------------------------------------ // Author : Common // 接口名:MyThread // 属性: // 方法: class MyThread_1 implements Runnable{ private String name; public MyThread_1(String name) { //构造方法 super(); this.name = name; } @Override public void run() { //覆写Thread类中的run()方法 // TODO 自动生成的方法存根 for (int i=0;i<10;i++){ System.out.println(name+"运行,i="+i); } } } //主类 //Function : Thread_demo public class Runnable_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 MyThread_1 mt1 = new MyThread_1("线程A "); //实例化Runnable子类对象 MyThread_1 mt2 = new MyThread_1("线程B "); //实例化Runnable子类对象 Thread t1 = new Thread(mt1); //实例化Thread类对象 Thread t2 = new Thread(mt2); //实例化Thread类对象 t1.start(); //启动线程 t2.start(); //启动线程 } }
通过Thread和Runnable接口都可以实现多线程,其中Thread类也是Runnable接口的子类,但在Thread类中并没有完全地实现Runnable接口中的run()方法。
区别:如果一个类继承了Thread类,则不适合多个线程共享资源,而实现了Runnable接口,就可以方便地实现资源的共享。
如果在Thread子类覆盖的run方法中编写了代码,也为Thread子类对象传递了一个Runnable对象,线程运行的时候执行的是子类的run方法(匿名内部类对象的构造方法如何调用非默认构造方法)
//================================================= // File Name : Thread_demo //------------------------------------------------------------------------------ // Author : Common // 接口名:MyThread // 属性: // 方法: class MyThread_2 implements Runnable{ private int ticket = 5; @Override public void run() { //覆写Thread类中的run()方法 // TODO 自动生成的方法存根 for (int i=0;i<10;i++){ if(ticket>0){ System.out.println("卖票:ticket="+ticket--); } } } } //主类 //Function : Thread_demo2 public class Runnable_demo2 { public static void main(String[] args) { // TODO 自动生成的方法存根 MyThread_2 mt = new MyThread_2(); //实例化Runnable子类对象 Thread t1 = new Thread(mt); //实例化Thread类对象 Thread t2 = new Thread(mt); //实例化Thread类对象 Thread t3 = new Thread(mt); //实例化Thread类对象 t1.start(); //启动线程 t2.start(); //启动线程 t3.start(); //启动线程 } }
在没有同步之前会出现下面这种情况
实现Runnable接口相对于继承Thread类来说,有下列优势:
<1>适合多个相同程序代码的线程去处理同一资源的情况
<2>可以避免由于Java的但继承特性带来的局限
<3>增强了程序的健壮性,代码能够被多个线程共享,代码和数据是独立的
线程的生命周期