java线程-Thread和Runnable的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程-Thread和Runnable的区别相关的知识,希望对你有一定的参考价值。

进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。

线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。

线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

多进程是指操作系统能同时运行多个任务(程序)。

多线程是指在同一程序中有多个顺序流在执行

在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。

Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。

一、多线程建立方式

Thread&Runnable分别模拟卖火车票

1、thread方式

class MyThread extends Thread
{
    private int ticketsCont=5; //一共有5张火车票

    private String name; //窗口, 也即是线程的名字

    public MyThread(String name){
        this.name=name;
    }

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

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();

    }
}

这样程序可以正常完成交互式运行。那么为啥非要使用start();方法启动多线程呢?

在JDK的安装路径下,src.zip是全部的java源程序,通过此代码找到Thread中的start()方法的定义,可以发现此方法中使用了private native void start0();其中native关键字表示可以调用操作系统的底层函数,那么这样的技术成为JNI技术(java Native Interface)。

2、Runnable方式

步骤:
     1,定义类实现Runnable接口
     2,覆盖Runnable接口中的run方法
          将线程要运行的代码存放在该run方法中
     3,通过Thread 类建立线程对象
     4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
          为什么要将Runnable接口中的子类对象传递给Thread的构造函数
          因为,自定义的run方法所属的对象是Runnable接口的子类对象
          所以要让线程去指定指定对象的run方法,就必须明确该run方法所属对象。
     5,调用Thread类的start方法 开启线程并调用Runnable接口子类的run方法

class MyThread2 implements Runnable
{
    private int ticketsCont=5; //一共有5张火车票
    
    @Override
    public void run(){
        
            
            while(true){
                 synchronized(this){
                    if(ticketsCont<=0){
                        break;
                    }
                    ticketsCont--; //如果还有票,就卖掉一张票
                    
                    System.out.println(Thread.currentThread().getName()+"卖掉了1张票,剩余票数为:"+ticketsCont);
                    
                    /*try{
                        Thread.sleep(50);  //通过阻塞程序来查看效果
                    }
                    catch(Exception e){
                        System.out.println(e);
                    }*/

                }
            }
        
    }

}

public class TicketsRunnable
{
    public static void main(String args[]){
        
        MyThread2 mt=new MyThread2();
        //创建三个线程来模拟三个售票窗口
        Thread th1=new Thread(mt,"窗口1");
        Thread th2=new Thread(mt,"窗口2");
        Thread th3=new Thread(mt,"窗口3");

        //启动三个线程,也即是三个窗口,开始卖票
        th1.start();
        th2.start();
        th3.start();
        

    }
}

但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有。此时观察Thread类,有一个构造方法:public Thread(Runnable targer)此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现的多线程。(start()可以协调系统的资源):

二、总结


技术分享

  • 创建:新建一个线程对象,如Thread thd=new Thread()
  • 就绪:创建了线程对象后,调用了线程的start()方法(此时线程知识进入了线程队列,等待获取CPU服务 ,具备了运行的条件,但并不一定已经开始运行了)
  • 运行:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run()方法里面的逻辑
  • 终止:线程的run()方法执行完毕,或者线程调用了stop()方法,线程便进入终止状态
  • 阻塞:一个正在执行的线程在某些情况系,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep()方法

在基于线程实现的多线程上(例子1),则总共开辟了三个窗口,在每个窗口卖了5张票,总共卖了15张票,无法实现资源共享,造成程序出错。

在基于Runnable是,利用同步共享,实现资源共享,则三个窗口总共卖了5张票。

建议使用Runnable这种方式创建线程。 程序中的同一资源指的是同一个Runnable对象。安全的卖票程序中需要加入同步synchronized。


参考文献

1、JAVA多线程Thread VS Runnable详解

2、Java中Runnable和Thread的区别












以上是关于java线程-Thread和Runnable的区别的主要内容,如果未能解决你的问题,请参考以下文章

Java中Runnable和Thread的区别

java线程-Thread和Runnable的区别

Java中Runnable和Thread的区别

Java中Runnable和Thread的区别

Java多线程中Thread与Runnable的区别

java中的线程问题——继承Thread VS 实现Runnable的区别