zoukankan      html  css  js  c++  java
  • Java学习笔记(八)——java多线程

    【前面的话】

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

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

    【线程定义】

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

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

    【实现方法】

       1. 第一种继承:Thread类

    1 class 类名extends Thread{
    2   方法1;
    3   方法2;
    4   ……
    5   public void run(){
    6     实现代码
    7    }
    8 }

       2. 第二种:实现Runnable接口

    1 class 类名 implements Runnable{
    2    方法1;
    3    方法2;
    4    ……
    5    public void run(){
    6      实现代码
    7    }
    8 }

    【三段代码】

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

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

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

    第一段代码:

     1 public class NoThreadTest {
     2     private String noThread1;
     3     public NoThreadTest(){
     4     }
     5     public NoThreadTest(String noThread1){
     6         this.noThread1=noThread1;
     7     }
     8     public void run(){
     9         for(int i=0;i<3;i++){
    10             System.out.println(noThread1+"非多线程运行结果                             "+i);
    11         }
    12     }
    13     public static void main(String[] args){
    14         NoThreadTest maintest1=new NoThreadTest("我是A");
    15         NoThreadTest maintest2=new NoThreadTest("我是B");
    16         maintest1.run();
    17         maintest2.run();
    18     }
    View Code

    执行结果:

    1 我是A非多线程运行结果                                 0
    2 我是A非多线程运行结果                                 1
    3 我是A非多线程运行结果                                 2
    4 我是B非多线程运行结果                                 0
    5 我是B非多线程运行结果                                 1
    6 我是B非多线程运行结果                                 2
    View Code

    第二段代码: 

     1 public class ThreadTest extends Thread {
     2     private String Thread1;
     3     public ThreadTest(){
     4     }
     5     public ThreadTest(String Thread1){
     6         this.Thread1=Thread1;
     7     }
     8     public void run(){
     9         for(int i=0;i<3;i++){//可以参看评论5进行修改,效果会好一些。
    10             System.out.println(Thread1+"多线程运行结果                                 "+i);
    11         }
    12     }
    13     public static void main(String[] args){
    14         ThreadTest maintest1=new ThreadTest("我是A");
    15         ThreadTest maintest2=new ThreadTest("我是B");
    16         maintest1.run();
    17         maintest2.run();
    18         System.out.println("..............我是分割线........................");
    19         maintest1.start();
    20         maintest2.start();
    21     }
    22 }
    View Code

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

     1 我是A多线程运行结果                                 0
     2 我是A多线程运行结果                                 1
     3 我是A多线程运行结果                                 2
     4 我是B多线程运行结果                                 0
     5 我是B多线程运行结果                                 1
     6 我是B多线程运行结果                                 2
     7 ..............我是分割线........................
     8 我是A多线程运行结果                                 0
     9 我是B多线程运行结果                                 0
    10 我是B多线程运行结果                                 1
    11 我是B多线程运行结果                                 2
    12 我是A多线程运行结果                                 1
    13 我是A多线程运行结果                                 2
    View Code

    第三段代码:

     1 public class ThreadTest2 implements Runnable {
     2     private String Thread1;
     3     public ThreadTest2(){
     4     }
     5     public ThreadTest2(String Thread1){
     6         this.Thread1=Thread1;
     7     }
     8     public void run(){
     9         for(int i=0;i<3;i++){//可以参看评论5,效果会好一些
    10             System.out.println(Thread1+"多线程运行结果                                 "+i);
    11         }
    12     }
    13     public static void main(String[] args){
    14         ThreadTest2 maintest1=new ThreadTest2("我是A");
    15         ThreadTest2 maintest2=new ThreadTest2("我是B");
    16         Thread maintest4=new Thread(maintest1);
    17         Thread maintest5=new Thread(maintest2);
    18         maintest1.run();
    19         maintest2.run();
    20         System.out.println("..............我是分割线1........................");
    21         maintest4.run();
    22         maintest5.run();
    23         System.out.println("..............我是分割线2........................");
    24         maintest4.start();
    25         maintest5.start();
    26     }
    27 }
    View Code

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

     1 我是A多线程运行结果                                 0
     2 我是A多线程运行结果                                 1
     3 我是A多线程运行结果                                 2
     4 我是B多线程运行结果                                 0
     5 我是B多线程运行结果                                 1
     6 我是B多线程运行结果                                 2
     7 ..............我是分割线1........................
     8 我是A多线程运行结果                                 0
     9 我是A多线程运行结果                                 1
    10 我是A多线程运行结果                                 2
    11 我是B多线程运行结果                                 0
    12 我是B多线程运行结果                                 1
    13 我是B多线程运行结果                                 2
    14 ..............我是分割线2........................
    15 我是B多线程运行结果                                 0
    16 我是B多线程运行结果                                 1
    17 我是B多线程运行结果                                 2
    18 我是A多线程运行结果                                 0
    19 我是A多线程运行结果                                 1
    20 我是A多线程运行结果                                 2
    View Code

    【代码分析】

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

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

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

         1)Runnerable接口实现run方法

     1 public
     2 interface Runnable {
     3     /**
     4      * When an object implementing interface <code>Runnable</code> is used 
     5      * to create a thread, starting the thread causes the object's 
     6      * <code>run</code> method to be called in that separately executing 
     7      * thread. 
     8      * <p>
     9      * The general contract of the method <code>run</code> is that it may 
    10      * take any action whatsoever.
    11      *
    12      * @see     java.lang.Thread#run()
    13      */
    14     public abstract void run();
    15 }
    View Code

         2)Thread类实现run方法。

    1 public void run() {
    2     if (target != null) {
    3         target.run();
    4     }
    5     }
    View Code

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

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

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

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

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

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

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

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

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

         代理主题角色:中间商。

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

        代码:

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

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

         运行结果:

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

        得出结论:

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

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

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

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

        3. native关键字

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

     1   public synchronized void start() {
     2         /**
     3      * This method is not invoked for the main method thread or "system"
     4      * group threads created/set up by the VM. Any new functionality added 
     5      * to this method in the future may have to also be added to the VM.
     6      *
     7      * A zero status value corresponds to state "NEW".
     8          */
     9         if (threadStatus != 0)
    10             throw new IllegalThreadStateException();
    11         group.add(this);
    12         start0();
    13         if (stopBeforeStart) {
    14         stop0(throwableFromStop);
    15     }
    16     }
    17 private native void start0();
    View Code

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

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

    【实现区别】

        1. 三段代码

         1)第一段:

     1 public class ThreadTest6 extends Thread {
     2     private int num=3;//定义飞机票的张数
     3     public void run(){
     4         for(int i=0;i<10;i++){
     5             if(num>0){
     6                 System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
     7             }
     8         }        
     9     }
    10     public static void main(String[] args){
    11         ThreadTest6 threadtest1=new ThreadTest6();
    12         ThreadTest6 threadtest2=new ThreadTest6();
    13         ThreadTest6 threadtest3=new ThreadTest6();
    14         threadtest1.start();
    15         threadtest2.start();
    16         threadtest3.start();
    17 
    18     }
    19 }
    View Code

          结果:

    1 Thread-1飞机票还剩余num= 3
    2 Thread-2飞机票还剩余num= 3
    3 Thread-2飞机票还剩余num= 2
    4 Thread-2飞机票还剩余num= 1
    5 Thread-0飞机票还剩余num= 3
    6 Thread-0飞机票还剩余num= 2
    7 Thread-0飞机票还剩余num= 1
    8 Thread-1飞机票还剩余num= 2
    9 Thread-1飞机票还剩余num= 1
    View Code

        2)第二段:

     1 public class ThreadTest5 implements Runnable {
     2     private int num=3;//定义飞机票的张数
     3     public void run(){
     4         for(int i=0;i<10;i++){
     5             if(num>0){
     6                 System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
     7             }
     8         }        
     9     }
    10     public static void main(String[] args){
    11         ThreadTest5 threadtest1=new ThreadTest5();
    12         ThreadTest5 threadtest2=new ThreadTest5();
    13         ThreadTest5 threadtest3=new ThreadTest5();
    14         Thread thread1=new Thread(threadtest1,"窗口1");
    15         Thread thread2=new Thread(threadtest2,"窗口2");
    16         Thread thread3=new Thread(threadtest3,"窗口3");
    17         thread1.start();
    18         thread2.start();
    19         thread3.start();
    20     }
    21 }
    View Code

          结果:

    1 窗口2飞机票还剩余num= 3
    2 窗口2飞机票还剩余num= 2
    3 窗口2飞机票还剩余num= 1
    4 窗口1飞机票还剩余num= 3
    5 窗口1飞机票还剩余num= 2
    6 窗口1飞机票还剩余num= 1
    7 窗口3飞机票还剩余num= 3
    8 窗口3飞机票还剩余num= 2
    9 窗口3飞机票还剩余num= 1
    View Code

         3)第三段:

     1 public class ThreadTest7 implements Runnable {
     2     private int num=3;//定义飞机票的张数
     3     public void run(){
     4         for(int i=0;i<10;i++){
     5             if(num>0){
     6                 System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
     7             }
     8         }        
     9     }
    10     public static void main(String[] args){
    11         ThreadTest7 threadtest1=new ThreadTest7();
    12         Thread thread1=new Thread(threadtest1,"窗口1");
    13         Thread thread2=new Thread(threadtest1,"窗口2");
    14         Thread thread3=new Thread(threadtest1,"窗口3");
    15         thread1.start();
    16         thread2.start();
    17         thread3.start();
    18     }
    19 }
    View Code

          结果:

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

        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

  • 相关阅读:
    初创团队的技术选择
    敏捷大数据流程
    深入分析Java Web技术内幕(修订版)
    重构大数据统计
    Robot Framework学习笔记(十一)------ 分层设计
    Robot Framework学习笔记(十)------Selenium2Library库
    Robot Framework学习笔记(九)------创建资源和用户关键字
    Robot Framework学习笔记(八)------ride标签使用
    robotframework学习笔记(七)------筛选执行用例
    chromedriver与chrome版本映射列表
  • 原文地址:https://www.cnblogs.com/xt0810/p/3558000.html
Copyright © 2011-2022 走看看