转载自:Java创建线程的两个方法

Java提供了线程类Thread来创建多线程的程序。其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象。每个Thread对象描述了一个单独的线程。要产生一个线程,有两种方法:

◆需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法; 
◆实现Runnalbe接口,重载Runnalbe接口中的run()方法。

为什么Java要提供两种方法来创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢?

在Java中,类仅支持单继承,也就是说,当定义一个新的类的时候,它只能扩展一个外部类.这样,如果创建自定义线程类的时候是通过扩展 Thread类的方法来实现的,那么这个自定义类就不能再去扩展其他的类,也就无法实现更加复杂的功能。因此,如果自定义类必须扩展其他的类,那么就可以使用实现Runnable接口的方法来定义该类为线程类,这样就可以避免Java单继承所带来的局限性。

还有一点最重要的就是使用实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享.

(1)通过扩展Thread类来创建多线程

假设一个影院有三个售票口,分别用于向儿童、成人和老人售票。影院为每个窗口放有100张电影票,分别是儿童票、成人票和老人票。三个窗口需要同时卖票,而现在只有一个售票员,这个售票员就相当于一个CPU,三个窗口就相当于三个线程。通过程序来看一看是如何创建这三个线程的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<span style="font-size: 16px;">public class MutliThreadDemo {
    public static void main(String [] args){
        MutliThread m1=new MutliThread("Window 1");
        MutliThread m2=new MutliThread("Window 2");
        MutliThread m3=new MutliThread("Window 3");
        m1.start();
        m2.start();
        m3.start();
    }
}
class MutliThread extends Thread{
    private int ticket=100;//每个线程都拥有100张票
    MutliThread(String name){
        super(name);//调用父类带参数的构造方法
    }
    public void run(){
        while(ticket>0){
            System.out.println(ticket--+" is saled by "+Thread.currentThread().getName());
        }
    }
}
</span>

程序中定义一个线程类,它扩展了Thread类。利用扩展的线程类在MutliThreadDemo类的主方法中创建了三个线程对象,并通过start()方法分别将它们启动。

从结果可以看到,每个线程分别对应100张电影票,之间并无任何关系,这就说明每个线程之间是平等的,没有优先级关系,因此都有机会得到CPU的处理。但是结果显示这三个线程并不是依次交替执行,而是在三个线程同时被执行的情况下,有的线程被分配时间片的机会多,票被提前卖完,而有的线程被分配时间片的机会比较少,票迟一些卖完。

可见,利用扩展Thread类创建的多个线程,虽然执行的是相同的代码,但彼此相互独立,且各自拥有自己的资源,互不干扰。

(2)通过实现Runnable接口来创建多线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<span style="font-size: 16px;">public class MutliThreadDemo2 {
    public static void main(String [] args){
        MutliThread m1=new MutliThread("Window 1");
        MutliThread m2=new MutliThread("Window 2");
        MutliThread m3=new MutliThread("Window 3");
        Thread t1=new Thread(m1);
        Thread t2=new Thread(m2);
        Thread t3=new Thread(m3);
        t1.start();
        t2.start();
        t3.start();
    }
}
class MutliThread implements Runnable{
    private int ticket=100;//每个线程都拥有100张票
    private String name;
    MutliThread(String name){
        this.name=name;
    }
    public void run(){
        while(ticket>0){
            System.out.println(ticket--+" is saled by "+name);
        }
    }
}
</span>

由于这三个线程也是彼此独立,各自拥有自己的资源,即100张电影票,因此程序输出的结果和(1)结果大同小异。均是各自线程对自己的100张票进行单独的处理,互不影响。

可见,只要现实的情况要求保证新建线程彼此相互独立,各自拥有资源,且互不干扰,采用哪个方式来创建多线程都是可以的。因为这两种方式创建的多线程程序能够实现相同的功能。

由于这三个线程也是彼此独立,各自拥有自己的资源,即100张电影票,因此程序输出的结果和例4.2.1的结果大同小异。均是各自线程对自己的100张票进行单独的处理,互不影响。

可见,只要现实的情况要求保证新建线程彼此相互独立,各自拥有资源,且互不干扰,采用哪个方式来创建多线程都是可以的。因为这两种方式创建的多线程程序能够实现相同的功能。

(3)通过实现Runnable接口来实现线程间的资源共享

现实中也存在这样的情况,比如模拟一个火车站的售票系统,假如当日从A地发往B地的火车票只有100张,且允许所有窗口卖这100张票,那么每一个窗口也相当于一个线程,但是这时和前面的例子不同之处就在于所有线程处理的资源是同一个资源,即100张车票。如果还用前面的方式来创建线程显然是无法实现的,这种情况该怎样处理呢?看下面这个程序,程序代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<span style="font-size: 16px;">public class MutliThreadDemo3 {
    public static void main(String [] args){
        MutliThread m=new MutliThread();
        Thread t1=new Thread(m,"Window 1");
        Thread t2=new Thread(m,"Window 2");
        Thread t3=new Thread(m,"Window 3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class MutliThread implements Runnable{
    private int ticket=100;//每个线程都拥有100张票
    public void run(){
        while(ticket>0){
            System.out.println(ticket--+" is saled by "+Thread.currentThread().getName());
        }
    }
}
</span>

结果正如前面分析的那样,程序在内存中仅创建了一个资源,而新建的三个线程都是基于访问这同一资源的,并且由于每个线程上所运行的是相同的代码,因此它们执行的功能也是相同的。

可见,如果现实问题中要求必须创建多个线程来执行同一任务,而且这多个线程之间还将共享同一个资源,那么就可以使用实现Runnable接口的方式来创建多线程程序。而这一功能通过扩展Thread类是无法实现的,读者想想看,为什么?

实现Runnable接口相对于扩展Thread类来说,具有无可比拟的优势。这种方式不仅有利于程序的健壮性,使代码能够被多个线程共享,而且代码和数据资源相对独立,从而特别适合多个具有相同代码的线程去处理同一资源的情况。这样一来,线程、代码和数据资源三者有效分离,很好地体现了面向对象程序设计的思想。因此,几乎所有的多线程程序都是通过实现Runnable接口的方式来完成的。

java创建多线程(转载)的更多相关文章

  1. JAVA创建多线程

    首先:线程与进程的区别是什么呢? 进程:正在运行的一个程序称之为一个进程,进程负责了内存空间的划分,从宏观的角度:windows是在同时执行多个程序 从微观的角度看,CPU是在快速的切换要执行的程序. ...

  2. java创建多线程的三种方式

    /***************************继承Thread类创建多线程************************/ public class FirstThread extends ...

  3. Java创建多线程的三种方法

    Java多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...

  4. java创建多线程&创建进程

    概述 并发和并行是即相似又有区别: 并行:指两个或多个事件在同一时刻发生: 并发:指两个或多个事件在同一时间段内发生. 进程是指一个内存中运行中的应用程序.每个进程都有自己独立的一块内存空间,一个应用 ...

  5. Java创建多线程和线程安全集合Vector

    public class Test { public static Vector<String> data = new Vector<String>(); public sta ...

  6. java创建多线程实现并行计算任务处理

    1.直接上代码一看明白: package multithreadingTest; class fblib extends Thread{ public static Integer fb(Intege ...

  7. Java 创建多线程的三种方法

    1. 继承Thread类2. 实现Runnable接口3. 匿名类的方式 注: 启动线程是start()方法,run()并不能启动一个新的线程

  8. JAVA之多线程的创建

    转载请注明源出处:http://www.cnblogs.com/lighten/p/5967853.html 1.概念 老调重弹,学习线程的时候总会牵扯到进程的概念,会对二者做一个区分.网上有较多的解 ...

  9. “全栈2019”Java多线程第三章:创建多线程之实现Runnable接口

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

随机推荐

  1. swift 如何使用OC中宏的功能

    swift中没有宏的概念,那么我们在swift使用宏的功能来提高效率呢? 一.使用关键字 let 来声明一个常量 存储相应的值,以下代码声明了常量  myColor 来存储一种指定的颜色 let my ...

  2. 报错---[UIApplication _runWithMainScene:transitionContext:completion:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3505.16/UIApplication.m:3294**

    原因: 新的SDK不允许在设置rootViewController之前做过于复杂的操作,导致在didFinishLaunchingWithOptions 结束后还没有设置rootViewControl ...

  3. SQL的几道题目

    1.构造数据插入方案表t_project_finish表 a)将addtime更新为当前时间的前一天 首先想到的是addtime=addtime-1,然后就开始验证这个想法. 插入一行数据,包括主键和 ...

  4. Java基本排序

    长度为N的数组升序排序 一,冒泡排序 public class BubbleSort { private double[] data; public BubbleSort(double[] data) ...

  5. 最小生成树------Kruskal算法

    Kruskal最小生成树算法的概略描述:1 T=Φ:2 while(T的边少于n-1条) {3 从E中选取一条最小成本的边(v,w):4 从E中删去(v,w):5 if((v,w)在T中不生成环) { ...

  6. SharePoint缓存导致访问慢解决

    产品发布到公网时,客户每次访问页面都很慢,经过查找原因,发现在服务器上的APPFabric缓存出错误了: APPFabric缓存服务作用:用作内存中缓存来存储应用程序访问的数据,从而提高应用程序性能. ...

  7. java面板

    import java.awt.Color; import java.awt.Container; import javax.swing.JFrame; import javax.swing.JLab ...

  8. oracle的sid

    SID是一个数据库的唯一标识符!是你在建立一个数据库时系统自动赋予的一个初始ID,虽说他和数据库名(DB_NAME)都是一个数据库的唯一标识符,但是在作用上就有不小区别.SID主要用于在一些DBA操作 ...

  9. N_F1_APPROVE

    package nc.bs.pub.action; import java.util.ArrayList; import java.util.Hashtable; import java.util.L ...

  10. Flume负载均衡配置

    flume负载均衡配置 集群DNS配置如下: hadoop-maser 192.168.177.162 machine-0192.168.177.158 machine-1191.168.177.16 ...