前言:最近看博客看到Thread和Runnable的区别,区别主要是两个:1.Thread实现了Runnable,但使用Thread需要继承丧失了继承其他类的能力,Runnable没有这个问题,因为使用中用实现代替了继承。2.Runnable可以共享数据。那为啥呢?
之前阅读博客:
demo:
1. 举个类似的例子
场景:一个班有50名同学,然后班主任介绍了一个插班生进来,人数变为51;接着副班主任也介绍了一个插班生进来,人数变成52。
对应demo:
package com.example.demo_13_runnable; public class RunnableTest { public static void main(String args[]){ Banji banji = new Banji(50); BanZhuRen banZhuRen = new BanZhuRen(banji); System.out.println("the number of banji is :" + banZhuRen.addChabanSheng().toString()); BanZhuRen fubanZhuRen = new BanZhuRen(banji); System.out.println("the number of banji is :" + fubanZhuRen.addChabanSheng().toString()); } } class BanZhuRen{ private Banji banji; public BanZhuRen(Banji banji){ this.banji = banji; } public Banji addChabanSheng(){ return banji.addChabanSheng(); } } class Banji{ private int numOfStudent = 50; Banji(int numOfStudent){ this.numOfStudent = numOfStudent; } public void setNumOfStudent(int numOfStudent) { this.numOfStudent = numOfStudent; } public int getNumOfStudent() { return numOfStudent; } public Banji addChabanSheng(){ this.numOfStudent++; return this; } @Override public String toString() { return numOfStudent + ""; } }
运行结果:
the number of banji is :51 the number of banji is :52 Process finished with exit code 0
解释:
班主任和副班主任能共享numOfStudent的原因就在于他们管的班是同一个班(同一个班级类),当然学生人数即numOfStudent也是共享的。
注意区别:
public class RunnableTest { public static void main(String args[]){ Banji banji = new Banji(50); BanZhuRen banZhuRen = new BanZhuRen(new Banji(50)); System.out.println("the number of banji is :" + banZhuRen.addChabanSheng().toString());
BanZhuRen fubanZhuRen = new BanZhuRen(new Banji(50)); System.out.println("the number of banji is : + fubanZhuRen.addChabanSheng().toString()); } }
2. 用Runnable举个类似上面的例子
这时候再写一个和上面类似的例子还是:
场景:一个班有50名同学,然后班主任介绍了一个插班生进来,人数变为51;接着副班主任也介绍了一个插班生进来,人数变成52。
对应demo(只是用Thread代替了自定义的班主任类):
package com.example.demo_13_runnable_levelup; public class RunnableTest { public static void main(String args[]) throws InterruptedException { Banji banji = new Banji(); Thread banZhuRen = new Thread(banji); banZhuRen.start(); Thread.sleep(200); System.out.println("the number of banji is :" + banji.toString()); Thread fubanZhuRen = new Thread(banji); fubanZhuRen.start(); Thread.sleep(200); System.out.println("the number of banji is :" + banji.toString()); } } class Banji implements Runnable{ private int numOfStudent = 50; @Override public void run() { addChabanSheng(); } public synchronized Banji addChabanSheng(){ this.numOfStudent++; return this; } @Override public String toString() { return numOfStudent + ""; } }
运行结果:
the number of banji is :51 the number of banji is :52 Process finished with exit code 0
解释:
班主任(Thread)和副班主任(Thread)能共享Runnable的参数numOfStudent的原因就在于他们管的班是同一个班(同一个Runnable类),当然学生人数即numOfStudent也是共享的。
PS:解释下为什么要睡200ms,由于Thread.start只要将线程状态变为可执行,并没有立刻跑起来,这取决于jvm。我尴尬地发现不加sleep会出现50 和 51的情况。
3.结合源码解释
对应源码如下:
/** * Allocates a new {@code Thread} object. This constructor has the same * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} * {@code (null, target, gname)}, where {@code gname} is a newly generated * name. Automatically generated names are of the form * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. * * @param target * the object whose {@code run} method is invoked when this thread * is started. If {@code null}, this classes {@code run} method does * nothing. */ public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); }
/** * Initializes a Thread. * * @param g the Thread group * @param target the object whose run() method gets called * @param name the name of the new Thread * @param stackSize the desired stack size for the new thread, or * zero to indicate that this parameter is to be ignored. */ private void init(ThreadGroup g, Runnable target, String name, long stackSize) { Thread parent = currentThread(); if (g == null) { g = parent.getThreadGroup(); } g.addUnstarted(); this.group = g; this.target = target; this.priority = parent.getPriority(); this.daemon = parent.isDaemon(); setName(name); init2(parent); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; tid = nextThreadID(); }
/** * If this thread was constructed using a separate * <code>Runnable</code> run object, then that * <code>Runnable</code> object's <code>run</code> method is called; * otherwise, this method does nothing and returns. * <p> * Subclasses of <code>Thread</code> should override this method. * * @see #start() * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ @Override public void run() { if (target != null) { target.run(); } }
解释:可以看到两个Thread的target参数其实是同一个Runnable对象,然后调用其run()方法就是用的同一个对象的run()方法,那自然共享Runnable里面的数据了。
4.总结
其实共享数据不是什么很稀奇的地方,同一个对象当然共享数据嘛。还是mark一下Thread 和 Runnable的区别吧:1.Thread实现了Runnable,但使用Thread需要继承丧失了继承其他类的能力,Runnable没有这个问题,因为使用中用实现代替了继承。2.Runnable可以共享数据。