【前面的话】

实际项目在用spring框架结合dubbo框架做一个系统,虽然也负责了一块内容,但是自己的能力还是不足,所以还需要好好学习一下基础知识,然后做一些笔记。希望做完了这个项目可以写一些dubbo框架和spring框架方面的总结。

学习过程中的小知识点总结,基础知识,选择阅读

【线程定义】

在学习操作系统的时候,学习过什么是进程,什么是线程,下面这只维基百科里面关于线程的定义,大家可以看一下:

定义:线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

【实现方法】

1. 第一种继承:Thread类

 class 类名extends Thread{
方法1;
方法2;
……
public void run(){
实现代码
}
}

2. 第二种:实现Runnable接口

 class 类名 implements Runnable{
方法1;
方法2;
……
public void run(){
实现代码
}
}

【三段代码】

第一段代码,就是一个很简单,就是和多线程没有关系的一段测试代码。

第二段代码,使用继承Thread的方法实现多线程。

第三段代码,使用实现Runnable接口的方法实现多线程。

第一段代码:

 public class NoThreadTest {
private String noThread1;
public NoThreadTest(){
}
public NoThreadTest(String noThread1){
this.noThread1=noThread1;
}
public void run(){
for(int i=0;i<3;i++){
System.out.println(noThread1+"非多线程运行结果 "+i);
}
}
public static void main(String[] args){
NoThreadTest maintest1=new NoThreadTest("我是A");
NoThreadTest maintest2=new NoThreadTest("我是B");
maintest1.run();
maintest2.run();
}

执行结果:

 我是A非多线程运行结果                                 0
我是A非多线程运行结果 1
我是A非多线程运行结果 2
我是B非多线程运行结果 0
我是B非多线程运行结果 1
我是B非多线程运行结果 2

第二段代码:

 public class ThreadTest extends Thread {
private String Thread1;
public ThreadTest(){
}
public ThreadTest(String Thread1){
this.Thread1=Thread1;
}
public void run(){
for(int i=0;i<3;i++){//可以参看评论5进行修改,效果会好一些。
System.out.println(Thread1+"多线程运行结果 "+i);
}
}
public static void main(String[] args){
ThreadTest maintest1=new ThreadTest("我是A");
ThreadTest maintest2=new ThreadTest("我是B");
maintest1.run();
maintest2.run();
System.out.println("..............我是分割线........................");
maintest1.start();
maintest2.start();
}
}

执行结果:(每一次执行的结果都是不一样的,这只是其中的某一种)

 我是A多线程运行结果                                 0
我是A多线程运行结果 1
我是A多线程运行结果 2
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
..............我是分割线........................
我是A多线程运行结果 0
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
我是A多线程运行结果 1
我是A多线程运行结果 2

第三段代码:

 public class ThreadTest2 implements Runnable {
private String Thread1;
public ThreadTest2(){
}
public ThreadTest2(String Thread1){
this.Thread1=Thread1;
}
public void run(){
for(int i=0;i<3;i++){//可以参看评论5,效果会好一些
System.out.println(Thread1+"多线程运行结果 "+i);
}
}
public static void main(String[] args){
ThreadTest2 maintest1=new ThreadTest2("我是A");
ThreadTest2 maintest2=new ThreadTest2("我是B");
Thread maintest4=new Thread(maintest1);
Thread maintest5=new Thread(maintest2);
maintest1.run();
maintest2.run();
System.out.println("..............我是分割线1........................");
maintest4.run();
maintest5.run();
System.out.println("..............我是分割线2........................");
maintest4.start();
maintest5.start();
}
}

执行结果:(每一次执行的结果都是不一样的,这只是其中的某一种)

 我是A多线程运行结果                                 0
我是A多线程运行结果 1
我是A多线程运行结果 2
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
..............我是分割线1........................
我是A多线程运行结果 0
我是A多线程运行结果 1
我是A多线程运行结果 2
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
..............我是分割线2........................
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
我是A多线程运行结果 0
我是A多线程运行结果 1
我是A多线程运行结果 2

【代码分析】

1. run方法和start方法的区别:

java核心技术中有这样一段话:不要调用Thread类或Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启动新线程。应该调用Thread.start方法。这个方法将创建一个执行run方法的新线程。

2. 在上面第三段代码中,ThreadTest2类,Thread类和Runnerable接口都实现了run方法。

1)Runnerable接口实现run方法

 public
interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}

2)Thread类实现run方法。

 public void run() {
if (target != null) {
target.run();
}
}

3)为什么要说这个?因为这个实现是使用了代理模式。

代理:一个角色代表另一个角色来完成某些特定的功能。

举个例子:大家都买过衣服,所以在买衣服的时候,一般有下面的角色:

购物者:我们一般是从代理商那里买衣服,我们并不和制造商进行交涉,我们不关心衣服是如何生产出来的。

代理商:代理商是从制造商那里拿衣服,并且代理商可以提供一些简单的服务,比如裁剪裤子等。

制造商:制造衣服,并且批发衣服给代理商。

我们从上面的行为中可以抽象出,一个行为就是卖衣服这个行为在代理商和制造商都有,如果购物者要买衣服,也需要以代理商和制造商卖衣服为前提。

从上面我们可以抽象出三个角色,并不是和上面对应的哈。

抽象主题角色:这个使我们可以抽象出来的角色。就是卖衣服这个行为。

代理主题角色:中间商。

实际被代理角色:制造商。

代码:

  • SellClothes.java(需要和接口名一样)
 //抽象主题角色:买衣服
public interface SellClothes {
void sellClothes();
}
  • Middleman.java
 //代理主题角色:中间商
public class Middleman implements SellClothes{
private SellClothes t;
public Middleman(SellClothes t) {
super();
this.t = t;
}
public void sellClothes() {
t.sellClothes();
System.out.println("我是中间商,我买的是制造商的衣服");
System.out.println("我是中间商,我还提供对裤子不合适的进行裁剪服务");
}
}
  • SellClothes.java

 //实际被代理角色
public class Manufacturer implements SellClothes{
public void sellClothes() {
System.out.println("我是制造商,我提供批发衣服服务");
}
}
  • Test.java
 public class Test {
public static void main(String[] args) {
Manufacturer t = new Manufacturer();
Middleman sellclothes = new Middleman(t);
sellclothes.sellClothes();
}
}

运行结果:

 我是制造商,我提供批发衣服服务
我是中间商,我买的是制造商的衣服
我是中间商,我还提供对裤子不合适的进行裁剪服务

    得出结论:

抽象主题角色:Runnable,提供run方法

代理主题角色:Thread类,提供run方法

实际被代理角色:ThreadTest2,也实现了run 方法

这就是代理主题模式,我希望我讲清楚了,哈哈

3. native关键字

在看到start()实现方法的时候,看到了如下一段代码:

   public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
private native void start0();

然后我好奇,native是什么关键字:

一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现

【实现区别】

1. 三段代码

1)第一段:

 public class ThreadTest6 extends Thread {
private int num=3;//定义飞机票的张数
public void run(){
for(int i=0;i<10;i++){
if(num>0){
System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
}
}
}
public static void main(String[] args){
ThreadTest6 threadtest1=new ThreadTest6();
ThreadTest6 threadtest2=new ThreadTest6();
ThreadTest6 threadtest3=new ThreadTest6();
threadtest1.start();
threadtest2.start();
threadtest3.start(); }
}

结果:

 Thread-1飞机票还剩余num= 3
Thread-2飞机票还剩余num= 3
Thread-2飞机票还剩余num= 2
Thread-2飞机票还剩余num= 1
Thread-0飞机票还剩余num= 3
Thread-0飞机票还剩余num= 2
Thread-0飞机票还剩余num= 1
Thread-1飞机票还剩余num= 2
Thread-1飞机票还剩余num= 1

2)第二段:

 public class ThreadTest5 implements Runnable {
private int num=3;//定义飞机票的张数
public void run(){
for(int i=0;i<10;i++){
if(num>0){
System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
}
}
}
public static void main(String[] args){
ThreadTest5 threadtest1=new ThreadTest5();
ThreadTest5 threadtest2=new ThreadTest5();
ThreadTest5 threadtest3=new ThreadTest5();
Thread thread1=new Thread(threadtest1,"窗口1");
Thread thread2=new Thread(threadtest2,"窗口2");
Thread thread3=new Thread(threadtest3,"窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}

结果:

 窗口2飞机票还剩余num= 3
窗口2飞机票还剩余num= 2
窗口2飞机票还剩余num= 1
窗口1飞机票还剩余num= 3
窗口1飞机票还剩余num= 2
窗口1飞机票还剩余num= 1
窗口3飞机票还剩余num= 3
窗口3飞机票还剩余num= 2
窗口3飞机票还剩余num= 1

3)第三段:

 public class ThreadTest7 implements Runnable {
private int num=3;//定义飞机票的张数
public void run(){
for(int i=0;i<10;i++){
if(num>0){
System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
}
}
}
public static void main(String[] args){
ThreadTest7 threadtest1=new ThreadTest7();
Thread thread1=new Thread(threadtest1,"窗口1");
Thread thread2=new Thread(threadtest1,"窗口2");
Thread thread3=new Thread(threadtest1,"窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}

结果:

 窗口1飞机票还剩余num= 3
窗口1飞机票还剩余num= 2
窗口1飞机票还剩余num= 1

2. 分析:

第一和第二段代码不管是使用Runnerable实现还是使用Thread实现,从结果可以看出三个线程每个线程均有num这个资源,如果把num看做是飞机票的话,那么每个线程都有三张飞机票。这不是我们实际中要得到的情况。

      要实现这个飞机售票程序,我们只能创建一个资源对象,但要创建多个线程去处理同一个资源对象,并且每个线程上所运行的是相同的程序代码。

      这就是第三段代码实现的结果,ThreadTest7只创建了一个资源对象——threadtest1。创建了三个线程,每个线程调用的是同一个threadtest1对象中的run()方法,访问的是同一个对象中的变量(num)的实例,这个程序满足了我们的需求。

3. 结论:

可见,实现Runnable接口相对于继承Thread类来说,有如下显著的好处: 
      (1)适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。 
      (2)可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。 
      (3)有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当共享访问相同的对象是,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。

【后面的话】

写一篇文章的过程是充满了乐趣的一次奇妙的旅程,有时“柳暗“,有时”花明“。但是当写完的时候如同一次旅行的结束,总会是有收获的。

分享:

  1. 10层以下,走楼梯
  2. 左手刷牙
  3. 公交车读书
  4. 持续早起早睡
  5. 出门的时候记得,“伸手要纸钱“——身份证,手机,钥匙,纸巾,钱包。

——TT

最新文章

  1. Android开发学习之路-图片颜色获取器开发(1)
  2. [Web API] Web API 2 深入系列(2) 消息管道
  3. 大数据系统之监控系统(二)Flume的扩展
  4. github:如何获取项目源代码
  5. 在VS中添加lib的简单方法
  6. [Linux]centOS7-1-1503-x86_64下安装VM-TOOLS
  7. DedeCms 建站随笔(一)
  8. QlikView线图高亮选择尺寸
  9. Base algorithm
  10. [leetcode-604-Design Compressed String Iterator]
  11. 201521123045 《Java程序设计》第7周学习总结
  12. Loj #3089. 「BJOI2019」奥术神杖
  13. 如何彻底卸载Jenkins
  14. SpringBoot 项目打包后运行报 org.apache.ibatis.binding.BindingException
  15. MFC VC++获取当前程序的运行路径
  16. 通过清华TUNA镜像源下载Android源码
  17. 安装ruby&amp;gem
  18. rabbitmq重装依赖的erlang 要注意
  19. MyBatis3 用log4j在控制台输出 SQL
  20. CAN总线标准帧

热门文章

  1. svg学习
  2. MyBatis框架的使用及源码分析(十二) ParameterHandler
  3. 梳排序Comb sort
  4. elasticsearch 创建索引,以及检索一条数据
  5. spoj104 highways 生成树计数(矩阵树定理)
  6. 20155335俞昆《java程序设计》第十周总结
  7. python大数据挖掘系列之淘宝商城数据预处理实战
  8. POJ 3061 Subsequence ( 尺取法)
  9. sublime在搜索的时候排除js文件
  10. python模块(requests,logging)