探Java多线程Thread类和Runnable接口之间的联系
首先复习一下Java多线程实现机制,Java实现多线程方法有如下这么几种:
1、继承了(extends)Thread类
2、实现了(implements)Runnable接口
也就是说 有如下两种情况
情况1: 继承Thread类。重写其方法run() . 然后new之、调用Start()方法
public class TestThread
{
private int i;
public static void main(String[] args)
{
// TODO 自动生成的方法存根
for(int i=0;i<50;i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==20)
{
new newThread_1("thread__1").start();
}
}
} }
class newThread_1 extends Thread
{
public newThread_1(String threadName)
{
super(threadName);
}
public void run()
{
for(int i=0;i<50;i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
方法2:实现Runnable接口 把实现接口的类new之 ,作为Thread的构造参数。
package com.chenjun.test; public class TestThread
{
/**
* @param args
*/
public static void main(String[] args)
{
// TODO 自动生成的方法存根
for(int i=0;i<50;i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==20)
{
new Thread(new newThread()).start();
}
}
}
} class newThread implements Runnable
{ @Override
public void run()
{
// TODO 自动生成的方法存根
for(int i=0;i<50;i++)
{
System.out.println(Thread.currentThread().getName()+":"+i);
}
} }
那么问题来了。到底是继承父类Thread方便呢,还是实现Runnable接口好呢? 众所周知,Java的面向对象特性里面不支持多重继承,但是允许某类实现多个接口,这个问题的答案是不言而喻的 。 如果可以不继承父类,那么就应当尽量避免继承。实现接口是个良好的编程风格
本文中对基础知识的回顾就到底为止。 接下来,探讨一下在不阅读Java SDK的源码的情况下, 劳资带你一起来推测一下JDk的Thread类和Runnable究竟是个神马子关系.
首先:我们先谈点“题外话” Java之设计模式——代理模式
1,什么是代理模式?
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。
2,策略模式有什么好处?
在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
3,代理模式一般涉及到的角色有:
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
4,应用场景举例:
比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时是这样的体现的
先说说这个场景中的要素:一种类型的女人,潘金莲,王婆,西门庆,后来扩展的贾氏也和西门庆勾上了,我们是假设的,然后西门庆找潘金莲happy,但潘金莲不好意思直接,就找个王婆代理呗。我们看看具体代码。
package com.yangguangfu.proxy;
/**
*
* @author 阿福(trygf521@126.com)<br>
*定义一种类型的女人,王婆和潘金莲都属于这个类型的女人
*/
public interface KindWoman { //这种女人能做什么事情呢?
public void makeEyesWithMan();//抛媚眼 public void happyWithMan();//和男人那个.... }
一种类型嘛,那肯定是接口,定义个潘金莲
package com.yangguangfu.proxy;
/**
*
* @author 阿福(trygf521@126.com)<br>
*定义一个潘金莲是什么样的人
*/
public class PanJinLian implements KindWoman{ @Override
public void happyWithMan() {
System.out.println("潘金莲和男人在做那个..."); } @Override
public void makeEyesWithMan() {
System.out.println("潘金莲抛媚眼..."); } }
再定义个丑陋的王婆
package com.yangguangfu.proxy;
/**
*
* @author 阿福(trygf521@126.com)<br>
*王婆这个人老聪明了,她太老了,是个男人都看不上她,
*但是她有智慧经验呀,他作为一类女人的代理!
*/
public class WangPo implements KindWoman { private KindWoman kindWoman; public WangPo(){
//默认的话是潘金莲的代理
this.kindWoman = new PanJinLian();
}
//她可以是KindWomam的任何一个女人的代理,只要你是这一类型
public WangPo(KindWoman kindWoman){
this.kindWoman = kindWoman;
} @Override
public void happyWithMan() {
//自己老了,干不了了,但可以叫年轻的代替。
this.kindWoman.happyWithMan(); } @Override
public void makeEyesWithMan() {
//王婆年纪大了,谁看她抛媚眼啊
this.kindWoman.makeEyesWithMan(); } }
两个女主角都上场了,该男主角了,定义个西门庆
package com.yangguangfu.proxy;
/**
*
* @author 阿福(trygf521@126.com)<br>
*水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下:
*如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很!
*/
public class XiMenQiang { /**
* @param args
*/
public static void main(String[] args) {
WangPo wangPo;
//把王婆叫出来
wangPo = new WangPo();
//然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏:
wangPo.makeEyesWithMan();
//看到没有表面是王婆在做,其实爽的是潘金莲
wangPo.happyWithMan(); } }
那这就是活生生的一个例子,通过代理人实现了某种目的,如果真去了王婆这个中间环节,直接西门庆和潘金莲勾搭,估计很难成就武松杀嫂事件。
那我们再考虑一下,水浒里面还有没有这类型的女人?有,卢俊义的老婆贾氏(就是和那个管家苟合的那个),这个名字起的:“贾氏”,那我们也让王婆做她的代理:
package com.yangguangfu.proxy;
/**
*
* @author 阿福(trygf521@126.com)<br>
*定义一个贾氏是什么样的人
*/
public class JiaShi implements KindWoman { @Override
public void happyWithMan() {
System.out.println("贾氏和男人在做那个..."); } @Override
public void makeEyesWithMan() {
System.out.println("贾氏抛媚眼..."); } }
接下来,西门庆勾潘金莲又勾引贾氏:
package com.yangguangfu.proxy; public class XiMenQiang { /**
* @param args
*/
public static void main(String[] args) {
WangPo wangPo;
//把王婆叫出来
wangPo = new WangPo();
//然后西门庆说,我要和潘金莲Happy
wangPo.makeEyesWithMan();
//看到没有表面是王婆在做,其实爽的是潘金莲
wangPo.happyWithMan(); //西门庆勾引贾氏
JiaShi jiaShi = new JiaShi();
wangPo = new WangPo(jiaShi);
wangPo.makeEyesWithMan();
wangPo.happyWithMan(); } }
说完这个故事,那我总结一下,代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同样一个接口呗。好了不多说了,慢慢体会吧。(注:此故事转载于http://yangguangfu.iteye.com/blog/815787博客)
好的,有点扯远了。 我们回来接着讨论Runnable和Thread类的关系问题。
听完这个很黄很暴力的故事,我想说,Thread类和Runnable接口两者之间有代理设计模式的模型在里面。信否? look! 看下面:
以下代码我写了很详细的注释,看完估计就对Thread和Runnable的关系知根知底了。比自己去阅读JDK代码好多了;
package com.chenjun.test; public class Test
{
/**
* @param args
*/
public static void main(String[] args)
{
// TODO 自动生成的方法存根
Demo1 demo1 = new Demo1();
demo1.start();
new MyThread(new MyRunnable() { //图个方便,用匿名内部类来试试 ,语法结构等价于 new Thread(new Runnable(){}).start();
@Override
public void run()
{
// TODO 自动生成的方法存根
System.out.println("匿名Demo is call the run()!!!");
}
}).start();
new MyThread(new Demo2()).start();
}
}
interface MyRunnable
{
public void run();
}
class MyThread implements MyRunnable //这里的MyThread类充当了 ”任何一个实现MuRunnable接口的类“ 的代理 (侧重理解这句话! )
{
private MyRunnable my_runnable; //模拟Thread类里面藏了一个Runnable接口的引用。跟上面潘金莲例子 Kingwomen类是不是异曲同工 ?
public MyThread(MyRunnable myRunnable)
{
// TODO 自动生成的构造函数存根
this.my_runnable = myRunnable;
}
public MyThread() //默认无参构造
{ }
public void run()
{
my_runnable.run(); //发生多态 ,父类引用直接调方法。等于调用其子类中实现的方法
} public void start() //start方法体内部其实就是run! 因为我们再做多线程程序的时候重写的是run,而启动线程的时候确调用的start。start执行的仍旧是run()方法
{
run();
}
} class Demo1 extends MyThread //模拟实现Thread类实现多线程
{
@Override
public void run()
{
System.out.println("Demo1 is call the run()!!!");
}
} class Demo2 implements MyRunnable //模拟实现Runnable接口类实现多线程
{ @Override
public void run()
{
// TODO 自动生成的方法存根
System.out.println("Demo2 is call the run()!!!");
} }
运行结果:
Demo1 is call the run()!!!
匿名Demo is call the run()!!!
Demo2 is call the run()!!!
怎么样。是不是和Thread和Runnable接口的模型一模一样?
探Java多线程Thread类和Runnable接口之间的联系的更多相关文章
- 多线程-----Thread类与Runnable接口的区别
第一个继承Thread类来实现多线程,其实是相当于拿出三件事即三个卖早餐10份的任务分别分给三个窗口,他们各做各的事各卖各的早餐各完成各的任务,因为MyThread继承Thread类,所以在newMy ...
- 多线程----Thread类,Runnable接口,线程池,Callable接口,线程安全
1概念 1.1进程 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 任务管理器中: 1.2线程 线程是进程中的一个执行单元 ...
- Java多线程和并发(三),Thread类和Runnable接口
目录 1.Thread和Runnable接口 三.Thread类和Runnable接口 1.Thread和Runnable接口
- 使用Thread类和Runnable接口实现多线程的区别
使用Thread类和Runnable接口实现多线程的区别 先看两种实现方式的步骤: public class ThreadDemo{ public static void main(String[] ...
- java多线程(二)之实现Runnable接口
一.java多线程方式2: 实现Runnable接口 好处:a. 可以避免由于java单继承带来的局限性. b. 适合多个相同的程序的代码去处理同一个资源的情况, 把线程与程序的代码, 数据有效分离, ...
- Thread类与Runnable接口的深入理解
Thread类与Runnable接口的深入理解1.Thread类实现了Runnable接口,实现run方法,其中target参数对应的就是一个Runnable接口的实现类 @Override publ ...
- 多线程, Thread类,Runnable接口
多线程 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程.一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序. 单线程程序:即,若有多个任务只能依次执 ...
- 几种创建线程方式Thread类和Runnable接口
对于很多想学习java的人来说,经常听别人说线程难,其实真正理解了线程后,一点都不会觉得线程难,这里我为大家梳理下线程的创建方式吧. 一.线程的创建方式有三种 1.继承Thread类 2.实现Runn ...
- Java 多线程之 Thread 类 和 Runnable 接口初步使用
目录 Thread 类 Thread之定义线程类 Thread之开启线程 Runnable 接口 Runnable 之定义线程类 Runnable 之开启线程 @ Thread 类 Thread 类是 ...
随机推荐
- C# 切换到二级域名,使用Cookie
之前的网站一直用的是一级域名,现因为其他原因,需要使用一个二级域名访问,原先的域名不用了. 使用二级域名后,发现Cookie一直取不到,分析代码发现,原来是需要在设置cookie的时候,把二级域名加上 ...
- Android.Study.Question
1. NullPointerException 1.1 发生该异常的原因. 1.2 解决方法有哪几种? try-catch 2. Eclipse 中 debug/run 两个模式,run 是relea ...
- php 数组指定位置插入数据单元
PHP array_splice() 函数 array_splice(array,offset,length,array) 参数 描述 array 必需.规定数组. offset 必需.数值.如果 ...
- Servlet会话管理二(Cookie)
Cookie是在HTTP协议下,将服务器传递给浏览器的的少量信息保存到浏览器客户端的一种技术,通过这种技术,即使在浏览器被关闭或链接中断的情况下,用户仍可以维护Cookie中的数据. Cookie是经 ...
- Homestead 修改 Homestead.yaml 文件后 vagrant up 报错的问题
一般情况是 TAB 和空格的问题. 虽然表面看来,缩进是一致的. 但是 TAB 没能替换为空格,从而导致问题. 解决: $ sudo vim /etc/vim/vimrc.local syntax o ...
- laravel错误1071 Specified key was too long; max key length is 1000 bytes
Laravel 5.5 环境,php artisan migrate 之后,出现错误如题. 检查了一下,代码是这样的: $table->increments('id'); $table-> ...
- windows 与 Linux SOCKET通讯
windows client 端口 // Def_win_client_socket_test.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" ...
- PHP + Redis 队列实战
环境 centos6.5 PHP5.3 Redis安装 #yum install redis 1.redis配置认证密码 #vi /etc/redis.conf requirepass mypass ...
- jrebel
jrebel 编辑 JRebel是一套JavaEE开发工具.JRebel允许开发团队在有限的时间内完成更多的任务修正更多的问题,发布更高质量的软件产品. JRebel是收费软件,用户可以在JReb ...
- SpringMVC 学习 九 SSM环境搭建 (二) Spring配置文件的编写
spring配置文件中需要干的事情 (一)开启 Service与pojo包的注解扫描 注意:spring 扫描与表对应的实体类,以及service层的类,不能用来扫描Controller层的类,因为 ...