java 中两种多线程的区别,start方法和run方法的启动区别

直接上代码看的更清晰:html

package org.thread.demo;  
public class MyThread extends Thread{  
        private String name;  
        public MyThread(String name) {  
            super();  
            this.name = name;  
        }  
        public void run(){  
        for(int i=0;i<10;i++){ 
             System.out.println("线程开始:"+this.name+",i="+i);  
        } 
    }  
}  

package org.thread.demo;  
public class ThreadDemo01 {  
        public static void main(String[] args) {  
        MyThread mt1=new MyThread("线程a");  
        MyThread mt2=new MyThread("线程b");  
        mt1.run();  
        mt2.run();  
    }  
}

  运行发现结果颇有规律,先第一个对象执行,而后第二个对象执行,并无相互运行。在JDK的文档中能够发现,一旦调用start方法,则会经过JVM找到run方法。下面启动start方法启动线程:java

package org.thread.demo;  
public class ThreadDemo01 {  
        public static void main(String[] args) {  
        MyThread mt1=new MyThread("线程a");  
        MyThread mt2=new MyThread("线程b");  
        mt1.start();  
        mt2.start();  
    }  
}

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

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

Runnable接口函数

在实际开发中一个多线程的操做不多使用Thread类,而是经过Runnable接口完成。this

package org.runnable.demo;  
public class MyThread implements Runnable{  
    private String name;  
    public MyThread(String name) {  
        this.name = name;  
    }
    public void run(){  
        for(int i=0;i<100;i++){  
            System.out.println("线程开始:"+this.name+",i="+i);  
        }  
    }  
}

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

package org.runnable.demo;  
import org.runnable.demo.MyThread;  
public class ThreadDemo01 {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread("线程a");  
        MyThread mt2=new MyThread("线程b");  
        new Thread(mt1).start();  
        new Thread(mt2).start();  
    }  
}

 

两种实现方式的区别和联系:操作系统

在程序开发中只要是多线程确定永远以实现Runnable接口为主,由于实现Runnable接口相比继承Thread类有以下好处:线程

  • 避免点继承的局限,一个类能够实现多个接口。code

  • 适合于资源的共享

以卖电影券程序为例,经过Thread类完成:

package org.demo.dff;  
public class MyThread extends Thread{  
    private int ticket=10;  
    public void run(){  
        for(int i=0;i<20;i++){  
            if(this.ticket>0){  
                System.out.println("卖电影券:ticket"+this.ticket--);  
            }  
        }  
    }  
}

下面经过三个线程对象,同时卖电影券:

package org.demo.dff;  
public class ThreadTicket {  
    public static void main(String[] args) {  
        MyThread mt1=new MyThread();  
        MyThread mt2=new MyThread();  
        MyThread mt3=new MyThread();  
        mt1.start();//每一个线程都各卖了10张,共卖了30张电影券  
        mt2.start();//但实际只有10张电影券,每一个线程都卖本身的电影券  
        mt3.start();//没有达到资源共享  
    }  
}

若是用Runnable就能够实现资源共享,下面看例子:

package org.demo.runnable;  
public class MyThread implements Runnable{  
    private int ticket=10;  
    public void run(){  
        for(int i=0;i<20;i++){  
            if(this.ticket>0){  
                System.out.println("卖电影券:ticket"+this.ticket--);  
            }  
        }  
    }  
}  
package org.demo.runnable;  
public class RunnableTicket {  
    public static void main(String[] args) {  
        MyThread mt=new MyThread();  
        new Thread(mt).start();//同一个mt,可是在Thread中就不能够,若是用同一个实例化对象mt,就会出现异常  
        new Thread(mt).start();new Thread(mt).start();  
    }  
}

 

虽然如今程序中有三个线程,可是一共卖了10张电影券,也就是说使用Runnable实现多线程能够达到资源共享目的。

Runnable接口和Thread之间的联系:

public class Thread extends Object implements Runnable

发现Thread类也是Runnable接口的子类。

 

Java线程中run和start方法的区别

    Thread类中run()和start()方法的区别以下:
        run()方法: 在本线程内调用该Runnable对象的run()方法,能够重复屡次调用;
        start()方法: 启动一个线程,调用该Runnable对象的run()方法,不能屡次启动一个线程;

package com.ljq.test;

public class ThreadTest {
    
    /**
     * 观察直接调用run()和用start()启动一个线程的差异 
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args){
        Thread thread=new ThreadDemo();
        //第一种
        //代表: run()和其余方法的调用没任何不一样,main方法按顺序执行了它,并打印出最后一句
        //thread.run();
        
        //第二种
        //代表: start()方法从新建立了一个线程,在main方法执行结束后,因为start()方法建立的线程没有运行结束,
        //所以主线程未能退出,直到线程thread也执行完毕.这里要注意,默认建立的线程是用户线程(非守护线程)
        //thread.start();
        
        //第三种
        //一、为何没有打印出100句呢?由于咱们将thread线程设置为了daemon(守护)线程,程序中只有守护线程存在的时候,是能够退出的,因此只打印了七句便退出了
        //二、当java虚拟机中有守护线程在运行的时候,java虚拟机会关闭。当全部常规线程运行完毕之后,
        //守护线程无论运行到哪里,虚拟机都会退出运行。因此你的守护线程最好不要写一些会影响程序的业务逻辑。不然没法预料程序到底会出现什么问题
        //thread.setDaemon(true);
        //thread.start();
        
        //第四种
        //用户线程能够被System.exit(0)强制kill掉,因此也只打印出七句
        thread.start();
        System.out.println("main thread is over");
        System.exit(1);
    }
    
    public static class ThreadDemo extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println("This is a Thread test"+i);
            }
        }
    }
}

放大招(哈哈),总结:

1) start:

        用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。经过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并无运行,一旦获得cpu时间片,就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

2) run:

        run()方法只是类的一个普通方法而已,若是直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径仍是只有一条,仍是要顺序执行,仍是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到多线程的目的。

总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,仍是在主线程里执行

相关文章
相关标签/搜索