1.概要
JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。本节,我们将探讨常用的实现多线程的2种方式:Thread和Runnable。至于第三种ExecutorService、Callable、Future的实现是属于java.util.concurrent包下的内容,我将单独设置一节去探讨。
2.Runnable简介
2.1 Runnable概述
Runnable是一个接口,该接口只包含了一个run无参方法。设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread类实现了Runnable。激活的意思是说某个线程已经启动并且尚未停止。
此外Runnable为非Thread子类的类提供了一种激活方式。通过实例化某个Thread实例并将自身作为运行目标,就可以运行实现Runnable的类而无须创建Thread的子类。大多数情况下,如果只想重写run()方法,而不重写其他Thread方法,那么应使用Runnable接口。这很重要,因为除非程序猿打算修改或增强类的基本行为,否则不应该创建子类。
2.2 Runnable源码
package java.lang;
public interface Runnable {
public abstract void run();
}
3.Thread简介
3.1 Thread概述
Thread是程序中的执行线程。Java虚拟机允许程序并发地运行多个执行线程。
Thread是一个类。它实现了Runnable接口。
3.2 Thread类声明
public class Thread implements Runnable {}
4.Thread和Runnable的区别
在程序开发中只要是多线程肯定永远以实现Runnable接口为主,
首先阐述实现Runnable的好处:
- Java不允许多继承,因此实现了Runnable接口的类可以再继承其他类
- 方便资源贡献,即可以共享一个对象实例。
其次,Thread实现多线程方式是:多个线程完成自己的任务。而Runnable实现多线程的方式是:多个线程共同完成一个任务。这是因为Thread(线程)已经是程序中的执行线程了。
5.Thread和Runnable的多线程示例
该示例也能看出Thread和Runnable实现多线程的区别
5.1Thread的多线程示例
package org.multithread.basic.realize;
public class TestThread {
public static void main(String[] args) {
MyThread t1 = new TestThread().new MyThread();
MyThread t2 = new TestThread().new MyThread();
MyThread t3 = new TestThread().new MyThread();
t1.start();
t2.start();
t3.start();
}
class MyThread extends Thread{
private int ticket =10;
@Override
public void run() {
for(int i = 0;i<5;i++){
if(this.ticket > 0){
System.out.println(this.getName()+"出售:ticket"+this.ticket--);
}
}
}
};
}
运行结果:
Thread-0出售:ticket10
Thread-2出售:ticket10
Thread-1出售:ticket10
Thread-2出售:ticket9
Thread-0出售:ticket9
Thread-0出售:ticket8
Thread-0出售:ticket7
Thread-0出售:ticket6
Thread-2出售:ticket8
Thread-1出售:ticket9
Thread-1出售:ticket8
Thread-1出售:ticket7
Thread-1出售:ticket6
Thread-2出售:ticket7
Thread-2出售:ticket6
结果说明:
- MyThread继承于Thread,它是自定义线程,每个MyThread都会出售5张ticket。
- 线程执行时乱序
5.2 Runnable的多线程示例
对上个程序进行改造,如下:
package org.multithread.basic.realize;
public class TestThread {
public static void main(String[] args) {
// MyThread t1 = new TestThread().new MyThread();
// MyThread t2 = new TestThread().new MyThread();
// MyThread t3 = new TestThread().new MyThread();
MyRunnable mr = new TestThread().new MyRunnable();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
Thread t3 = new Thread(mr);
t1.start();
t2.start();
t3.start();
}
class MyThread extends Thread{
private int ticket =10;
@Override
public void run() {
for(int i = 0;i<5;i++){
if(this.ticket > 0){
System.out.println(this.getName()+"出售:ticket"+this.ticket--);
}
}
}
};
class MyRunnable implements Runnable{
private int ticket = 10;
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<5;i++){
if(this.ticket > 0){
System.out.println(Thread.currentThread().getName()+"出售:ticket"+this.ticket--);
}
}
}
};
}
运行结果:
Thread-1出售:ticket10
Thread-1出售:ticket7
Thread-1出售:ticket6
Thread-2出售:ticket8
Thread-2出售:ticket4
Thread-2出售:ticket3
Thread-2出售:ticket2
Thread-2出售:ticket1
Thread-0出售:ticket9
Thread-1出售:ticket5
结果说明:
- 主线程创建并启动了3个子线程,而且这3个子线程都是基于mr这个Runnable对象创建。
- 这3个子线程一共卖出了10张ticket。这说明3个子线程资源共享
6 总结
通过以上学习,我们了解到实现多线程的两种方式:继承Thread和实现Runnable接口,但是记住一条:在多线程开发中,要以实现Runnable接口为主,这是因为Java是单根继承,可以多个实现,继承Thread的类不能再继承其他类。并且Thread是执行线程,每个子线程之间相互独立,资源不共享。
来源:oschina
链接:https://my.oschina.net/u/2808406/blog/748445