JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。在这里我们主要说明前两中方式。
1.继承Thread类实现多线程
Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
一个简单的实例
public class MyThread extends Thread {
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + "运行 : " + i);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread t1=new MyThread("A");
MyThread t2=new MyThread("B");
t1.start();
t2.start();
}
}
运行结果
可能是: 也可能是:
因为需要用到CPU的资源,所以每次的运行结果基本是都不一样的。虽然我们在这里调用的是start()方法,但是实际上调用的还是run()方法的主体。
2.通过实现Runnable接口
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口。
先看一个实例
public class MyThread implements Runnable {
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + "运行 : " + i);
}
}
public static void main(String[] args) {
MyThread t1=new MyThread("线程A");
Thread demo1= new Thread(t1);
MyThread t2=new MyThread("线程B");
Thread demo2=new Thread(t2);
demo1.start();
demo2.start();
}
}
运行结果:
为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例。
其实Thread中的run方法调用的是Runnable接口的run方法。不知道大家发现没有,Thread和Runnable都实现了run方法,这种操作模式其实就是代理模式。
class Thread implements Runnable {
public void run() {
if (target != null) {
target.run();
}
}
}
3.Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
继承Thread类
public class MyThread extends Thread {
private int ticket = 4;
public void run() {
for (int i = 0; i < 5; i++) {
if (ticket > 0) {
System.out.println("车票还有 " + ticket-- +"张");
}
}
}
public static void main(String[] args) {
MyThread h1 = new MyThread();
MyThread h2 = new MyThread();
MyThread h3 = new MyThread();
h1.start();
h2.start();
h3.start();
}
}
运行结果:
这里并没有实现资源的共享,我们换为Runnable接口
public class MyThread implements Runnable {
private int ticket = 4;
public void run() {
for (int i=0; i<=20; i++) {
if (this.ticket > 0) {
System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);
}
}
}
public static void main(String[] args) {
MyThread my = new MyThread();
new Thread(my, "1号窗口").start();
new Thread(my, "2号窗口").start();
new Thread(my, "3号窗口").start();
}
}
运行结果:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。