Java多线程之Thread VS Runnable(根据慕课网视频编写)

线程创建的两种方式比较
继承Thread类:

class MyThread extends Thread{
    ......
    @Override
    public void run(){
    ......
    }
}

MyThread mt=new MyThread();//创建线程
mt.start();                //启动线程

实现Runnable接口:

class MyThread implements Runnable{
    ......
    @Override
    public void run(){
    ......
    }
}

MyThread mt=new MyThread();
Thread td=new Thread(mt);//创建线程
td.start();              //启动线程

从这两种方式可以看出,无论是哪种方式我们创建线程都要new出来一个thread类的对象,启动对象,要调用thread类的start方法。

两种方式比较:
1.Java中一个子类,可以实现多个接口,但是只能继承一个父类。所以Runnable方式可以避免Thread方式由于Java单继承特性带来的缺陷。
2.Runnable的代码可以被多个线程(Thread实例)共享,适合于多个线程处理同一资源的情况。(以下用代码模拟卖票举例说明。)
Thread&Runnable分别模拟卖火车票
我们模拟火车站3个窗口总共卖5张票的情况。

•Thread方式

class MyThread extends Thread{

    private int ticketsCount=5; //一共有5张火车票
    private String name; //窗口, 也即是线程的名字
    public MyThread(String name){
        this.name=name;
    }
    @Override
    public void run(){      
       while(ticketsCount>0){
            ticketsCount--; //如果还有票,就卖掉一张票
            System.out.println(name+"卖掉了1张票,剩余票数为:"+ticketsCount);
        }       
    }
}
public class TicketsThread{

    public static void main(String args[]){       
        //创建三个线程,模拟三个窗口卖票
        MyThread mt1=new MyThread("窗口1");
        MyThread mt2=new MyThread("窗口2");
        MyThread mt3=new MyThread("窗口3");

        //启动三个线程,也即是窗口,开始卖票
        mt1.start();
        mt2.start();
        mt3.start();
    }
}

输出结果:

窗口3卖掉了1张票,剩余票数为:4
窗口3卖掉了1张票,剩余票数为:3
窗口3卖掉了1张票,剩余票数为:2
窗口1卖掉了1张票,剩余票数为:4
窗口1卖掉了1张票,剩余票数为:3
窗口1卖掉了1张票,剩余票数为:2
窗口1卖掉了1张票,剩余票数为:1
窗口1卖掉了1张票,剩余票数为:0
窗口2卖掉了1张票,剩余票数为:4
窗口3卖掉了1张票,剩余票数为:1
窗口2卖掉了1张票,剩余票数为:3
窗口2卖掉了1张票,剩余票数为:2
窗口3卖掉了1张票,剩余票数为:0
窗口2卖掉了1张票,剩余票数为:1
窗口2卖掉了1张票,剩余票数为:0

结果确是每个窗口卖了5张票,这个和我们期望的明显不一样。我们待会分析,先看Runnable接口下模拟卖票的情况。

•Runnable方式

class MyThread implements Runnable {
    private int ticketsCount = 5; // 一共有5张火车票

    public void run() {
        while (ticketsCount > 0) {
            ticketsCount--; // 如果还有票,就卖掉一张票
            System.out.println(Thread.currentThread().getName()
                    + "卖掉了1张票,剩余票数为:" + ticketsCount);
        }
    }
}

public class TicketsRunnable {

    public static void main(String[] args) {
        MyThread mt = new MyThread();
        //创建三个线程来模拟三个售票窗口
        Thread th1 = new Thread(mt, "窗口1");
        Thread th2 = new Thread(mt, "窗口2");
        Thread th3 = new Thread(mt, "窗口3");
        //启动三个线程,也即是三个窗口,开始卖票
        th1.start();
        th2.start();
        th3.start();
    }
}

输出结果:

窗口1卖掉了1张票,剩余票数为:4
窗口2卖掉了1张票,剩余票数为:3
窗口2卖掉了1张票,剩余票数为:0
窗口3卖掉了1张票,剩余票数为:2
窗口1卖掉了1张票,剩余票数为:1

这里的输出结果是随机的,剩余票数并不是一定为43210的原因是,出现了资源的抢占。可以理解为,A窗口票已经卖掉了,然后票据正在打印。正在A窗口打印票据的时候,B窗口也卖了一张,并且打印的比A窗口快,先打印出票据。

分析
Thread方式中,我们new了3个线程,每个线程都有自己的ticketsCount,3个ticketsCount是独立的,不是共享的,所以卖出了15张票。

线程的生命周期
这里写图片描述

•创建:新建一个线程对象,如Thread thd=new Thread()

•就绪:创建了线程对象后,调用了线程的start()方法(此时线程知识进入了线程队列,等待获取CPU服务 ,具备了运行的条件,但并不一定已经开始运行了)

•运行:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run()方法里面的逻辑

•终止:线程的run()方法执行完毕,或者线程调用了stop()方法,线程便进入终止状态

•阻塞:一个正在执行的线程在某些情况系,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep()方法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值