java多线程——线程的创建

Posted 今夕何希

tags:

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

java多线程——线程的创建

1、创建线程方式一:继承Thread类

(1)定义一个类继承Thread;

(2)重写run方法;

(3)创建线程对象;

(4)调用start方法,开启线程并让线程执行,同时还会告诉JVM调用run方法。

技术分享图片
 1 class Demo extends Thread{
 2     private String name;
 3     Demo(String name){
 4         this.name=name;
 5     }
 6     @Override
 7     public void run() {
 8         for(int i=1;i<=20;i++) {
 9             System.out.println("name="+name+"......."+i);
10         }
11     }
12 }
13 
14 public class ThreadDemo {
15     public static void main(String[] args) {
16         //method0();
17         //method1();
18         Demo d1=new Demo("小强");
19         Demo d2=new Demo("旺财");
20         d2.start();//开启多一个执行路径
21         d1.run();//由主线程负责
22     }
23 
24     public static void method1() {
25         Demo d1=new Demo("小强");
26         Demo d2=new Demo("旺财");
27         d1.run();//由主线程负责
28         d2.start();//开启多一个执行路径,主线程结束才开启
29     }
30 
31     public static void method0() {
32         Demo d1=new Demo("小强");
33         Demo d2=new Demo("旺财");
34         d1.run();//由主线程负责
35         d2.run();//由主线程负责
36     }        
37 }
ThreadDemo

以上代码中,method1和method0运行效果相同,但是method1确实开启了多线程,只是在主线程结束后才开启。

线程对象调用run方法和调用start方法的区别?

调用run方法不开启线程,仅是对象调用方法;调用start开启线程,并让JVM调用run方法在开启的线程中执行。

为什么要继承Thread类并重写run方法?

因为Thread类描述的是线程事物,具备线程该有的功能。既然如此?为什么不能直接创建Thread类的对象:Thread t1=new Thread(); t1.start();这种写法没有错,但是该start方法调用的是Thread类中的run方法,而这个run方法没有任何操作,更重要的是,这个run方法中没有定义我们需要让线程执行的代码。创建线程的目的是为了建立单独的路径,让多部分代码实现同时执行。也就是说,线程创建并执行需要给定的代码(线程的任务)。对于我们常用的主线程,它的任务都定义在main函数中。自定义线程需要执行的任务都定义在run方法中。Thread类中的run方法内部的任务不是我们所需要,所以需要进行run方法的重写。

内存占用:多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间,进行方法的压栈和弹栈。当执行线程的任务结束了,线程自动在栈内存中释放了。当所有的执行线程都结束了,进程就结束了。

2、创建线程方式二:实现Runnable接口

(1)声明一个类实现Runnable接口(避免了继承Thread类的单继承局限性)。

(2)该类实现run方法(将线程任务代码定义到run方法中)。

(3)创建Thread类的对象(只有创建Thread类的对象才能创建线程)。

(4)将Runnable接口的子类对象作为参数传递给Thread类的构造函数。

(5)启动线程。

 

技术分享图片
 1 //)声明一个类实现Runnable接口,该类实现run方法。
 2 class Demo2 implements Runnable{
 3     private String name;
 4     Demo2(String name){
 5         this.name=name;
 6     }
 7     @Override
 8     public void run() {
 9         for(int i=1;i<=20;i++) {
10             System.out.println("name="+name+"....."+Thread.currentThread().getName()+"...."+i);
11         }
12     }
13 }
14 
15 public class ThreadDemo2 {
16     public static void main(String[] args) {
17         //(2)创建Runnable子类的对象
18         Demo2 d1=new Demo2("小强");
19         Demo2 d2=new Demo2("旺财");
20         //(3)创建Thread类的对象,将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
21         Thread t1=new Thread(d1);
22         Thread t2=new Thread(d2);
23         //(4)启动线程。
24         t1.start();
25         t2.start();
26         for(int i=0;i<20;i++) {
27             System.out.println(Thread.currentThread().getName()+"----->"+i);
28         }
29         
30     }
31 }
ThreadDemo2

 

在Thread类中相关源码抽离出来如下:

 1 public class Thread {
 2     private Runnable target;
 3     public Thread(Runnable target){
 4         this.target=target;
 5     }
 6     
 7     public void run() {
 8         if (target != null) {
 9             target.run();
10         }
11     }    
12 }

优点(避免单继承+解耦):

第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。

实现Runnable接口的方式,更加符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既有线程对象,又有线程任务。而Runnable接口,将线程任务单独分离出来,封装成对象,类型就是Runnable接口类型。

 


以上是关于java多线程——线程的创建的主要内容,如果未能解决你的问题,请参考以下文章

多个请求是多线程吗

Java多线程系列-线程创建

Java多线程-线程池的使用与线程总结(狂神说含代码)

Java多线程——Lock&Condition

java-多线程创建

Java多线程——多线程的基本概念和使用