直接上代码看的更清晰:html
package org.thread.demo; public class MyThread extends Thread{ private String name; public MyThread(String name) { super(); this.name = name; } public void run(){ for(int i=0;i<10;i++){ System.out.println("线程开始:"+this.name+",i="+i); } } } package org.thread.demo; public class ThreadDemo01 { public static void main(String[] args) { MyThread mt1=new MyThread("线程a"); MyThread mt2=new MyThread("线程b"); mt1.run(); mt2.run(); } }
运行发现结果颇有规律,先第一个对象执行,而后第二个对象执行,并无相互运行。在JDK的文档中能够发现,一旦调用start方法,则会经过JVM找到run方法。下面启动start方法启动线程:java
package org.thread.demo; public class ThreadDemo01 { public static void main(String[] args) { MyThread mt1=new MyThread("线程a"); MyThread mt2=new MyThread("线程b"); mt1.start(); mt2.start(); } }
这样程序能够正常完成交互式运行。那么为啥非要使用start方法启动多线程呢?多线程
在JDK的安装路径下,src.zip是所有的java源程序,经过此代码找到Thread中的start方法的定义,能够发现此方法中使用了private native void start0();其中native关键字表示能够调用操做系统的底层函数,那么这样的技术称为JNI技术(java Native Interface)ide
Runnable接口函数
在实际开发中一个多线程的操做不多使用Thread类,而是经过Runnable接口完成。this
package org.runnable.demo; public class MyThread implements Runnable{ private String name; public MyThread(String name) { this.name = name; } public void run(){ for(int i=0;i<100;i++){ System.out.println("线程开始:"+this.name+",i="+i); } } }
可是在使用Runnable定义的子类中没有start方法,只有Thread类中才有。此时观察Thread类,有一个构造方法:public Thread(Runnable targer) 此构造方法接受Runnable的子类实例,也就是说能够经过Thread类来启动Runnable实现的多线程。(start方法能够协调系统的资源):spa
package org.runnable.demo; import org.runnable.demo.MyThread; public class ThreadDemo01 { public static void main(String[] args) { MyThread mt1=new MyThread("线程a"); MyThread mt2=new MyThread("线程b"); new Thread(mt1).start(); new Thread(mt2).start(); } }
两种实现方式的区别和联系:操作系统
在程序开发中只要是多线程确定永远以实现Runnable接口为主,由于实现Runnable接口相比继承Thread类有以下好处:线程
避免点继承的局限,一个类能够实现多个接口。code
适合于资源的共享
以卖电影券程序为例,经过Thread类完成:
package org.demo.dff; public class MyThread extends Thread{ private int ticket=10; public void run(){ for(int i=0;i<20;i++){ if(this.ticket>0){ System.out.println("卖电影券:ticket"+this.ticket--); } } } }
下面经过三个线程对象,同时卖电影券:
package org.demo.dff; public class ThreadTicket { public static void main(String[] args) { MyThread mt1=new MyThread(); MyThread mt2=new MyThread(); MyThread mt3=new MyThread(); mt1.start();//每一个线程都各卖了10张,共卖了30张电影券 mt2.start();//但实际只有10张电影券,每一个线程都卖本身的电影券 mt3.start();//没有达到资源共享 } }
若是用Runnable就能够实现资源共享,下面看例子:
package org.demo.runnable; public class MyThread implements Runnable{ private int ticket=10; public void run(){ for(int i=0;i<20;i++){ if(this.ticket>0){ System.out.println("卖电影券:ticket"+this.ticket--); } } } } package org.demo.runnable; public class RunnableTicket { public static void main(String[] args) { MyThread mt=new MyThread(); new Thread(mt).start();//同一个mt,可是在Thread中就不能够,若是用同一个实例化对象mt,就会出现异常 new Thread(mt).start();new Thread(mt).start(); } }
虽然如今程序中有三个线程,可是一共卖了10张电影券,也就是说使用Runnable实现多线程能够达到资源共享目的。
Runnable接口和Thread之间的联系:
public class Thread extends Object implements Runnable
发现Thread类也是Runnable接口的子类。
Thread类中run()和start()方法的区别以下:
run()方法: 在本线程内调用该Runnable对象的run()方法,能够重复屡次调用;
start()方法: 启动一个线程,调用该Runnable对象的run()方法,不能屡次启动一个线程;
package com.ljq.test; public class ThreadTest { /** * 观察直接调用run()和用start()启动一个线程的差异 * * @param args * @throws Exception */ public static void main(String[] args){ Thread thread=new ThreadDemo(); //第一种 //代表: run()和其余方法的调用没任何不一样,main方法按顺序执行了它,并打印出最后一句 //thread.run(); //第二种 //代表: start()方法从新建立了一个线程,在main方法执行结束后,因为start()方法建立的线程没有运行结束, //所以主线程未能退出,直到线程thread也执行完毕.这里要注意,默认建立的线程是用户线程(非守护线程) //thread.start(); //第三种 //一、为何没有打印出100句呢?由于咱们将thread线程设置为了daemon(守护)线程,程序中只有守护线程存在的时候,是能够退出的,因此只打印了七句便退出了 //二、当java虚拟机中有守护线程在运行的时候,java虚拟机会关闭。当全部常规线程运行完毕之后, //守护线程无论运行到哪里,虚拟机都会退出运行。因此你的守护线程最好不要写一些会影响程序的业务逻辑。不然没法预料程序到底会出现什么问题 //thread.setDaemon(true); //thread.start(); //第四种 //用户线程能够被System.exit(0)强制kill掉,因此也只打印出七句 thread.start(); System.out.println("main thread is over"); System.exit(1); } public static class ThreadDemo extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("This is a Thread test"+i); } } } }
放大招(哈哈),总结:
1) start:
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。经过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并无运行,一旦获得cpu时间片,就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
2) run:
run()方法只是类的一个普通方法而已,若是直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径仍是只有一条,仍是要顺序执行,仍是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到多线程的目的。
总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,仍是在主线程里执行