实现多线程的两种方法:继承Thread类或实现Runnable接口

实现多线程的两种方法:继承Thread类或实现Runnable接口

Java中实现多线程有两种方法:继承Thread类和实现Runnable接口,在程序开发中只要是多线程,我们一般都是实现Runnable接口,原因归结为一点:实现接口比继承类要好。

多线程的第一种实现方式:继承Thread类

步骤如下

  • 创建一个继承Thread的类(假定为A),并重写Thread的run方法
  • 构造一个A类对象,假定为aa
  • 调用aa的start方法。(start方法是从Thread继承过来的)

具体例子如下

package org.wrh.concurrent;
/*
 * 火车站多站点卖票程序
 * */
class MyThread extends Thread{
    private int ticketNum = 10;
    public void run(){
        for (int i=0;i<10;i++)
        {
            if(ticketNum > 0){
                System.out.println(Thread.currentThread().getName()+"    正在卖第 " + ticketNum+"张票");
                ticketNum--;
            }
        }
    }
}  

public class ThreadDemo01{
    public static void main(String[] args){
        /*
         * 共三个线程对象,分别为各个线程制定了线程的名字
         * */
       Thread t1= new MyThread();
       t1.setName("线程A");
       t1.start();
       Thread t2= new MyThread();
       t2.setName("线程B");
       t2.start();
       Thread t3= new MyThread();
       t3.setName("线程C");
       t3.start(); 

    }
}

程序运行的结果如下:

线程A 正在卖第 10张票

线程B 正在卖第 10张票

线程A 正在卖第 9张票

线程B 正在卖第 9张票

线程A 正在卖第 8张票

线程B 正在卖第 8张票

线程C 正在卖第 10张票

线程C 正在卖第 9张票

线程C 正在卖第 8张票

线程C 正在卖第 7张票

线程C 正在卖第 6张票

线程C 正在卖第 5张票

线程C 正在卖第 4张票

线程C 正在卖第 3张票

线程C 正在卖第 2张票

线程C 正在卖第 1张票

线程A 正在卖第 7张票

线程A 正在卖第 6张票

线程A 正在卖第 5张票

线程A 正在卖第 4张票

线程A 正在卖第 3张票

线程A 正在卖第 2张票

线程A 正在卖第 1张票

线程B 正在卖第 7张票

线程B 正在卖第 6张票

线程B 正在卖第 5张票

线程B 正在卖第 4张票

线程B 正在卖第 3张票

线程B 正在卖第 2张票

线程B 正在卖第 1张票

从结果中可以看出,A、B、C三个线程每个线程相互独立的卖了10张票,但实际的火车站售票中,是需要多个线程去共同去卖N张票。

注意

  • Thread中start方法的功能是创建一个新的线程,并自动调用该线程的run方法,直接调用run方法是不会创建一个新的线程的。
  • 执行一个线程实际上就是执行该线程的run方法里面的代码。
  • 执行完aa.start()方法后并不表示aa所对应的线程就一定会得到执行,只是表示此线程具有了被CPU立即执行的资格。但由于想抢占CPU执行的线程很多,CPU并不一定会立即执行aa所对应的线程。线程的执行由操作系统控制:优先级、时间长短、最长等待时间等。
  • 一个Thread对象不能调用两次start(),否则会抛出异常。

多线程的第二种实现方式:实现Runnable接口

步骤如下:

  • 定义一个实现了Runnable接口的类,假定为A
  • 创建A类的对象aa
  • 利用aa构造一个Thread对象tt,Thread tt=new Thread(aa)
  • 调用tt的start方法:`tt.start()
package org.wrh.concurrent;

class MyThread_1 implements Runnable{
    private int ticketNum = 20;
    public void run(){
        for (int i=0;i<10;i++)
        {
            if(ticketNum > 0){
                System.out.println(Thread.currentThread().getName()+"    正在卖第 " + ticketNum+"张票");
                ticketNum--;
            }
        }
    }
}  

public class ThreadDemo02{
    public static void main(String[] args){
        MyThread_1 my = new MyThread_1();
        new Thread(my).start();
        new Thread(my).start();
        new Thread(my).start();
    }
}

程序运行结果如下:

Thread-1 正在卖第 20张票

Thread-2 正在卖第 20张票

Thread-0 正在卖第 20张票

Thread-2 正在卖第 18张票

Thread-1 正在卖第 19张票

Thread-2 正在卖第 16张票

Thread-0 正在卖第 17张票

Thread-2 正在卖第 14张票

Thread-1 正在卖第 15张票

Thread-2 正在卖第 12张票

Thread-0 正在卖第 13张票

Thread-2 正在卖第 10张票

Thread-1 正在卖第 11张票

Thread-2 正在卖第 8张票

Thread-0 正在卖第 9张票

Thread-2 正在卖第 6张票

Thread-1 正在卖第 7张票

Thread-2 正在卖第 4张票

Thread-0 正在卖第 5张票

Thread-2 正在卖第 2张票

Thread-1 正在卖第 3张票

Thread-0 正在卖第 1张票

从上面结果可以看出:

  • 第一点:这三个线程并不是相互独立的卖20张票,而是一起卖20张票。
  • 第二点:这三个线程卖票的过程中有冲突,例如,都卖第20张票,

产生第二点的原因为:

一个线程在判断ticketNum为20>0后,还没有来得及减1,另一个线程此时也判断ticketNum为20>0,还没有来得及减1,那么接下来第三个线程开始执行发现ticketNum还是20>0,于是就这样三个线程把第20张票卖了3次。这就需要加入同步操作(即互斥锁),确保同一时刻只有一个线程在执行每次for循环中的操作。而在第一种方法中,并不需要加入同步操作,因为每个线程执行自己Thread对象中的代码,不存在多个线程共同执行同一个方法的情况。

加同步操作后的代码如下:

package org.wrh.concurrent;

class MyThread_1 implements Runnable{
    private int ticketNum = 20;
    public synchronized void run(){
        for (int i=0;i<10;i++)
        {
              if(ticketNum > 0){
                System.out.println(Thread.currentThread().getName()+"    正在卖第 " + ticketNum+"张票");
                ticketNum--;
            }
        }
    }
}  

public class ThreadDemo02{
    public static void main(String[] args){
        MyThread_1 my = new MyThread_1();
        new Thread(my).start();
        new Thread(my).start();
        new Thread(my).start();
    }
}

上面的代码只是在原有的代码的基础上在run方法前加上了synchronized关键字来限定即可完成了锁的功能。

程序的结果如下:

Thread-0 正在卖第 20张票

Thread-0 正在卖第 19张票

Thread-0 正在卖第 18张票

Thread-0 正在卖第 17张票

Thread-0 正在卖第 16张票

Thread-0 正在卖第 15张票

Thread-0 正在卖第 14张票

Thread-0 正在卖第 13张票

Thread-0 正在卖第 12张票

Thread-0 正在卖第 11张票

Thread-2 正在卖第 10张票

Thread-2 正在卖第 9张票

Thread-2 正在卖第 8张票

Thread-2 正在卖第 7张票

Thread-2 正在卖第 6张票

Thread-2 正在卖第 5张票

Thread-2 正在卖第 4张票

Thread-2 正在卖第 3张票

Thread-2 正在卖第 2张票

Thread-2 正在卖第 1张票

总共买了20张票,且每张票只卖了一次,这就是实现了同步锁的功能

最后对线程控制的基本方法进行一个介绍

(1)isAlive():判断线程是否还“活”着,即线程是否还未终止

(2)getPriority():获得线程的优先级数值,0表示线程优先级最高。

(3)setPriority():设置线程的优先级

(4)join():用线程对象调用,如果在一个线程A中调用另一个线程B的join方法,线程A将会等待线程B执行完毕后再执行。

(5)yield():让出CPU,当前线程进入就绪队列等待调度。直接用Thread类调用,yield让出CPU执行权给同等级的线程,如果没有相同级别的线程在等待CPU的执行权,则该线程继续执行

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 22:57:04

实现多线程的两种方法:继承Thread类或实现Runnable接口的相关文章

Java基础知识强化之多线程笔记05:Java中继承thread类 与 实现Runnable接口的区别

1. Java中线程的创建有两种方式:  (1)通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中. (2)通过实现Runnable接口,实例化Thread类. 2. 在实际应用中,我们经常用到多线程,如车站的售票系统,车站的各个售票口相当于各个线程.当我们做这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,现在看一下这两种方式实现的两种结果. 继承thread类 1 package com.threadtest; 2 clas

Java中实现多线程继承Thread类与实现Runnable接口的区别

Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 在实际应用中,我们经常用到多线程,如车站的售票系统,车站的各个售票窗口相当于各个线程.当我们做这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,现在看一下这两种方式实现的两种结果. 一:继承Thread类的方式 Java代码 package com.threadtest; cl

Java中继承thread类与实现Runnable接口的区别

Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 在实际应用中,我们经常用到多线程,如车站的售票系统,车站的各个售票口相当于各个线程.当我们做这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,现在看一下这两种方式实现的两种结果. Java代码   package com.threadtest; class MyThread e

Java线程示例 - 继承Thread类和实现Runnable接口

进程(Process)和线程(Thread)是程序运行的两个基本单元.Java并发编程更多的是和线程相关. 进程 进程是一个独立的执行单元,可将其视为一个程序或应用.然而,一个程序内部同事还包含多个进程.Java运行时环境就是一个单独的进程,在它内部还包含了作为进程的各种类和程序. 线程 可以将线程看做轻量级的进程.线程存在于进程当中,需要的资源开销较小.同一进程中的线程共享进程的资源. Java多线程 每一个Java引用都只要有一个线程 - 主线程(main thread).虽然后台还运行着许

Java线程演示样例 - 继承Thread类和实现Runnable接口

进程(Process)和线程(Thread)是程序执行的两个基本单元. Java并发编程很多其它的是和线程相关. 进程 进程是一个独立的执行单元,可将其视为一个程序或应用.然而,一个程序内部同事还包括多个进程. Java执行时环境就是一个单独的进程,在它内部还包括了作为进程的各种类和程序. 线程 能够将线程看做轻量级的进程. 线程存在于进程其中,须要的资源开销较小.同一进程中的线程共享进程的资源. Java多线程 每个Java引用都仅仅要有一个线程 - 主线程(main thread).尽管后台

在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口

//继承thread类 class PrimeThread extends Thread{ long minPrime; PrimeThread(long minPrime) { this.minPrime=minPrime; } public void run(){ //computer primes larger than minPrime } } //调用方法 PrimeThread p=new PrimeThread(143); p.start(); //调用Runnable接口 cla

Java通过继承thread类与实现Runnable接口实现多线程的区别

Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 一.通过继承Thread类实现多线程 class MyThread extends Thread{ String name = null; int ticket = 0; public MyThread(String name){ this.name = name; } public synchronized v

【多线程学习记录一(2)】继承Thread类和实现Runnable接口、Callable接口的区别

1)Runnable和Callable同是接口 * Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void);call方法可以抛出异常,run方法不可以 * 运行Callable任务可以拿到一个Future对象,表示异步计算的结果.它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果.通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果. * 加入线程池运行,Runnable使用ExecutorService的execute方

多线程_创建线程_继承Thread类

public class ThreadDemo {   public static void main(String[] args){         Demo d = new Demo();   d.start();      for(int i = 0;i < 100;i++){      System.out.println("MainThread" + i);   }   } } class Demo extends Thread {   public void run(