1、通过实现Runnable接口创建线程
(1).定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
(2).创建Runnable接口实现类的对象。
(3).创建一个Thread类的对象,需要封装前面Runnable接口实现类的对象。(接口可以实现多继承)
(4).调用Thread对象的start()方法,启动线程
- public class ThreadFromRunnable implements Runnable {
int count = 10;
public void run() {
System.out.println("\t#"+Thread.currentThread().getName()+" 开始count值 " + count);
while(count > 0)
{
count--;
System.out.println("#"+Thread.currentThread().getName()+" : count-- "+ count);
}
System.out.println("#"+Thread.currentThread().getName()+" : 最后count值 "+ count--);
}
public static void main(String[] args)
{
ThreadFromRunnable tr = new ThreadFromRunnable();
Thread thread = new Thread(tr);
Thread thread2 = new Thread(tr);
thread.start();
thread2.start();
}
}
output:
#Thread-0 开始count值 10
#Thread-1 开始count值 10
#Thread-0 : count-- 9
#Thread-1 : count-- 8
#Thread-0 : count-- 7
#Thread-1 : count-- 6
#Thread-0 : count-- 5
#Thread-0 : count-- 3
#Thread-1 : count-- 4
#Thread-0 : count-- 2
#Thread-1 : count-- 1
#Thread-0 : count-- 0
#Thread-1 : 最后count值 0
#Thread-0 : 最后count值 -1
=====================================================================
public class ThreadFromRunnable implements Runnable {
//int count = 10;
public void run() {
int count = 10; //起不到共享的效果了,局部变量,没意义!!!!!!!!!!!!!!!!!肯定是每个线程独享的!
System.out.println("\t#"+Thread.currentThread().getName()+" 开始count值 " + count);
while(count > 0)
{
count--;
System.out.println("#"+Thread.currentThread().getName()+" : count-- "+ count);
}
System.out.println("#"+Thread.currentThread().getName()+" : 最后count值 "+ count--);
}
public static void main(String[] args)
{
ThreadFromRunnable tr = new ThreadFromRunnable();
Thread thread = new Thread(tr);
Thread thread2 = new Thread(tr);
thread.start();
thread2.start();
}
}
结果如下:
#Thread-0 开始count值 10
#Thread-1 开始count值 10
#Thread-0 : count-- 9
#Thread-1 : count-- 9
#Thread-0 : count-- 8
#Thread-0 : count-- 7
#Thread-0 : count-- 6
#Thread-0 : count-- 5
#Thread-0 : count-- 4
#Thread-0 : count-- 3
#Thread-0 : count-- 2
#Thread-1 : count-- 8
#Thread-0 : count-- 1
#Thread-1 : count-- 7
#Thread-0 : count-- 0
#Thread-1 : count-- 6
#Thread-0 : 最后count值 0
#Thread-1 : count-- 5
#Thread-1 : count-- 4
#Thread-1 : count-- 3
#Thread-1 : count-- 2
#Thread-1 : count-- 1
#Thread-1 : count-- 0
#Thread-1 : 最后count值 0
=====================================================================
2、通过继承Thread类创建线程
(1).首先定义一个类去继承Thread父类,重写父类中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
(2).直接创建一个ThreadDemo2类的对象,也可以利用多态性,变量声明为父类的类型。
(3).调用start方法,线程t启动,隐含的调用run()方法。
public class ThreadExtendsThread extends Thread {
int count =10;
public void run()
{
System.out.println("\t#"+Thread.currentThread().getName()+" got count from " + count);
while(count > 0)
{
count--;
System.out.println(this.getName()+" : existing count=" + count);}
}
public static void main(String[] args)
{
ThreadExtendsThread thread = new ThreadExtendsThread();
ThreadExtendsThread thread2 = new ThreadExtendsThread();
thread.start();
thread2.start();
}
}
结果:
#Thread-0 got count from 10
#Thread-1 got count from 10
Thread-0 : existing count=9
Thread-1 : existing count=9
Thread-0 : existing count=8
Thread-1 : existing count=8
Thread-0 : existing count=7
Thread-1 : existing count=7
Thread-0 : existing count=6
Thread-1 : existing count=6
Thread-0 : existing count=5
Thread-1 : existing count=5
Thread-0 : existing count=4
Thread-1 : existing count=4
Thread-0 : existing count=3
Thread-1 : existing count=3
Thread-0 : existing count=2
Thread-1 : existing count=2
Thread-0 : existing count=1
Thread-1 : existing count=1
Thread-0 : existing count=0
Thread-1 : existing count=0
=====================================================================
- public class ThreadExtendsThread extends Thread {
- //int count =10;
- public void run()
- {
- int count=10; //局部变量,没意义!!!!!!!!!!!!!!!
- System.out.println("\t#"+Thread.currentThread().getName()+" got count from " + count);
- while(count > 0)
- {
- System.out.println("{1}quot;+this.getName()+" : "+count--);
- }
- System.out.println("{1}quot;+this.getName()+" : existing count=" + count);
- }
- public static void main(String[] args)
- {
- ThreadExtendsThread thread = new ThreadExtendsThread();
- ThreadExtendsThread thread2 = new ThreadExtendsThread();
- thread.start();
- thread2.start();
- }
- }
#Thread-0 got count from 10
#Thread-1 got count from 10
$Thread-1 : 10
$Thread-1 : 9
$Thread-1 : 8
$Thread-1 : 7
$Thread-1 : 6
$Thread-1 : 5
$Thread-1 : 4
$Thread-1 : 3
$Thread-1 : 2
$Thread-1 : 1
$Thread-0 : 10
$Thread-1 : existing count=0
$Thread-0 : 9
$Thread-0 : 8
$Thread-0 : 7
$Thread-0 : 6
$Thread-0 : 5
$Thread-0 : 4
$Thread-0 : 3
$Thread-0 : 2
$Thread-0 : 1
$Thread-0 : existing count=0
=====================================================================
3、两种方式的比较
首先分析两种方式的输出结果,同样是创建了两个线程,为什么结果不一样呢?
使用实现Runnable接口方式创建线程可以共享同一个目标对象(TreadDemo1 tt=new TreadDemo1();),实现了多个相同线程处理同一份资源。
然后再看一段来自JDK的解释:
The Runnable
interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments calledrun
.
This interface is designed to provide a common protocol for objects that wish to execute code while they are active. For example,Runnable
is implemented by classThread
. Being active simply means that a thread has been started and has not yet been stopped.
In addition, Runnable
provides the means for a class to be active while not subclassingThread
. A class that implementsRunnable
can run without subclassingThread
by instantiating aThread
instance and passing itself in as the target. In most cases, theRunnable
interface should be used if you are only planning to override therun()
method and no otherThread
methods. This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class.
采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
1、如果extends Thread后就不能extends其他类了
2、如果implements Runnable,那还是要将这个对象传到Thread的构造方法中,new出一个线程对象,
3、implements Runnable能让多个线程共享同一个对象
4、1)一般认为:实现Runnable接口的对象,其着眼点主要含义是:一个计算任务.它代表一个要被其它线程(如:线程池中的线程)执行的任务.着眼点是:交由其它人去完成的一个计算任务. ---对应着:要做的工作 ;
2)一般认为:从Thread类继承的含义主要是:一个能执行其它(或自己)的任务的一个线程对象.着眼点是:线程的功能(通过继承来扩展执行其它计算任务的能力) ---对应着:做工作的工作人员
下面看例子: 1 package org.thread.demo; 2 class MyThread extends Thread{ 4 public MyThread(String name) { 5 super(); 6 this.name = name; 7 } 8 public void run(){ 9 for(int i=0;i<10;i++){ 10 System.out.println("线程开端:"+this.name+",i="+i); 11 } 12 } 13 } 14 package org.thread.demo; 15 public class ThreadDemo01 { 16 public static void main(String[] args) { 17 MyThread mt1=new MyThread("线程a"); 18 MyThread mt2=new MyThread("线程b"); 19 mt1.run(); 20 mt2.run(); 21 } 22 } 然而,此时后果很有法则,先第一个对象执行,而后第二个对象执行,并没有彼此运行 。在JDK的文档中 可以发现,一旦调用start() 步骤,则会通过JVM找到run() 步骤 。下面启动start() 步骤启动线程: 23 package org.thread.demo; 24 public class ThreadDemo01 { 25 public static void main(String[] args) { 26 MyThread mt1=new MyThread("线程a"); 27 MyThread mt2=new MyThread("线程b"); 28 mt1.start(); 29 mt2.start(); 30 } 31 }; 这样程序 可以畸形实现交互式运行 。那么为啥非要 使用start(); 步骤启动多线程呢? 在JDK的安装路径下,src.zip是所有的java源程序,通过此代码找到Thread中的start() 步骤的定义, 可以发现此步骤中 使用了private native void start0();其中native 要害字示意 可以调用操作系统的底层函数,那么这样的技术成为JNI技术(javaNativeInterface) Runnable接口 在实际开辟中一个多线程的操作很少 使用Thread类,而是通过Runnable接口实现 。 32 public interface Runnable{ 33 public void run(); 34 } 例子: 35 package org.runnable.demo; 36 class MyThread implements Runnable{ 37 private String name; 38 public MyThread(String name) { 39 this.name = name; 40 } 41 public void run(){ 42 for(int i=0;i<100;i++){ 43 System.out.println("线程开端:"+this.name+",i="+i); 44 } 45 } 46 }; 然而在 使用Runnable定义的子类中没有start() 步骤,惟独Thread类中才有 。此时视察Thread类,有一个构造 步骤:public Thread(Runnable targer)此 构造步骤承受Runnable的子类实例,也便是说 可以通过Thread类来启动Runnable实现的多线程 。(start() 可以协调系统的资源): 47 package org.runnable.demo; 48 import org.runnable.demo.MyThread; 49 public class ThreadDemo01 { 50 public static void main(String[] args) { 51 MyThread mt1=new MyThread("线程a"); 52 MyThread mt2=new MyThread("线程b"); 53 new Thread(mt1).start(); 54 new Thread(mt2).start(); 55 } 56 } 两种实现 模式的区别和联络: 在程序开辟中惟独是多线程确定永远以实现Runnable接口为主,由于实现Runnable接口相比继承Thread类有如下 好处: · 幸免点继承的局限,一个类 可以继承多个接口 。 · 合适于资源的共享 以卖票程序为例,通过Thread类实现: 57 package org.demo.dff; 58 class MyThread extends Thread{ 59 private int ticket=10; 60 public void run(){ 61 for(int i=0;i<20;i++){ 62 if(this.ticket>0){ 63 System.out.println("卖票:ticket"+this.ticket--); 64 } 65 } 66 } 67 }; 下面通过三个线程对象,同时卖票: 68 package org.demo.dff; 69 public class ThreadTicket { 70 public static void main(String[] args) { 71 MyThread mt1=new MyThread(); 72 MyThread mt2=new MyThread(); 73 MyThread mt3=new MyThread(); 74 mt1.start();//每个线程都各卖了10张,共卖了30张票 75 mt2.start();//但实际惟独10张票,每个线程都卖自己的票 76 mt3.start();//没有达到资源共享 77 } 78 } 假如用Runnable就 可以实现资源共享,下面看例子: 79 package org.demo.runnable; 80 class MyThread implements Runnable{ 81 private int ticket=10; 82 public void run(){ 83 for(int i=0;i<20;i++){ 84 if(this.ticket>0){ 85 System.out.println("卖票:ticket"+this.ticket--); 86 } 87 } 88 } 89 } 90 package org.demo.runnable; 91 public class RunnableTicket { 92 public static void main(String[] args) { 93 MyThread mt=new MyThread(); 94 new Thread(mt).start();//同一个mt,然而在Thread中就不 可以,假如用同一 95 new Thread(mt).start();//个实例化对象mt,就会浮现 异样 96 new Thread(mt).start(); 97 } 98 }; 固然现在程序中有三个线程,然而一共卖了10张票,也便是说 使用Runnable实现多线程 可以达到资源共享目标 。 Runnable接口和Thread中间的联络: public class Thread extends Object implements Runnable 发现Thread类也是Runnable接口的子类 。
|