zoukankan      html  css  js  c++  java
  • Java中两种实现多线程方式的对比分析

    本文转载自:http://www.linuxidc.com/Linux/2013-12/93690.htm#0-tsina-1-14812-397232819ff9a47a7b7e80a40613cfe1

      

      Java中有两种实现多线程的方式。一是直接继承Thread类,二是实现Runnable接口。那么这两种实现多线程的方式在应用上有什么区别呢?

      为了回答这个问题,我们可以通过编写一段代码来进行分析。我们用代码来模拟铁路售票系统,实现通过四个售票点发售某日某次列车的100张车票,一个售票点用一个线程表示。

      我们首先这样编写这个程序:

    public class ThreadDome1{
    
      public static void main(String[] args){
    
        ThreadTest t = new ThreadTest();
        t.start();
        t.start();
        t.start();
        t.start();
      }
    
    }
    
    class ThreadTest extends Thread{ private int ticket = 100; public void run(){ while(true){ if(ticket > 0){ System.out.println(Thread.currentThread().getName() + "is saling ticket" + ticket--); }else{ break; } } } }

      上面的代码中,我们用ThreadTest类模拟售票处的售票过程,run方法中的每一次循环都将总票数减1,模拟卖出一张车票,同时该车票号打印出来,直接剩余的票数到零为止。在ThreadDemo1类的main方法中,我们创建了一个线程对象,并重复启动四次,希望通过这种方式产生四个线程。从运行的结果来看我们发现其实只有一个线程在运行,这个结果告诉我们:一个线程对象只能启动一个线程,无论你调用多少遍start()方法,结果只有一个线程。

          我们接着修改ThreadDemo1,在main方法中创建四个Thread对象:

    public class ThreadDemo1{
    
      public static void main(String[] args){
    
        new ThreadTest().start();
        new ThreadTest().start();
        new ThreadTest().start();
        new ThreadTest().start();
      }
    }
    
    
    class ThreadTest extends Thread{
    
      private int ticket = 100;
    
      public void run(){
        while(true){
          if(ticket > 0){
            System.out.println(Thread.currentThread().getName() + 
              " is saling ticket" + ticket--);
          }else{
            break;
          }
        }
      }
    }

        这下达到目的了吗?

        从结果上看每个票号都被打印了四次,即四个线程各自卖各自的100张票,而不去卖共同的100张票。这种情况是怎么造成的呢?我们需要的是,多个线程去处理同一个资源,一个资源只能对应一个对象,在上面的程序中,我们创建了四个ThreadTest对象,就等于创建了四个资源,每个资源都有100张票,每个线程都在独自处理各自的资源。

        经过这些实验和分析,可以总结出,要实现这个铁路售票程序,我们只能创建一个资源对象,但要创建多个线程去处理同一个资源对象,并且每个线程上所运行的是相同的程序代码。在回顾一下使用接口编写多线程的过程。

    public class ThreadDemo1{
    
      public static void main(String[] args){
    
        ThreadTest t = new ThreadTest();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    
      }
    
    }
    
    class ThreadTest implements Runnable{
    
      private int tickets = 100;
    
      public void run(){
        while(true){
          if(tickets > 0){
            System.out.println(Thread.currentThread().getName() +
              " is saling ticket " + tickets--);
          } else {
          break;
        }
        }
      }
    }

      上面的程序中,创建了四个线程,每个线程调用的是同一个ThreadTest对象中的run()方法,访问的是同一个对象中的变量(tickets)的实例,这个程序满足了我们的需求。在Windows上可以启动多个记事本程序一样,也就是多个进程使用同一个记事本程序代码。

      可见,实现Runnable接口相对于继承Thread类来说,有如下显著的好处:

      (1)适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。

      (2)可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。

      (3)有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。

  • 相关阅读:
    [DB] 数据库的连接
    JS leetcode 翻转字符串里的单词 题解分析
    JS leetcode 拥有最多糖果的孩子 题解分析,六一快乐。
    JS leetcode 搜索插入位置 题解分析
    JS leetcode 杨辉三角Ⅱ 题解分析
    JS leetcode 寻找数组的中心索引 题解分析
    JS leetcode 移除元素 题解分析
    JS leetcode 最大连续1的个数 题解分析
    JS leetcode 两数之和 II
    JS leetcode 反转字符串 题解分析
  • 原文地址:https://www.cnblogs.com/hqbhonker/p/4775243.html
Copyright © 2011-2022 走看看