创建线程的两种方式

朴灿烈づ我的快乐病毒、 2022-01-09 12:57 420阅读 0赞

先来了解一下与线程相关的概念,如程序,进程,以及他们之间的区别

1)、程序Program:

程序是一段静态的代码, 它是应用程序执行的蓝本。

2)、进程Process

进程是指一种正在运行的程序, 有自己的地址空间。

3)、线程Thread

进程内部的一个执行单元, 它是程序中一个单一的顺序控制流程。线程又被称为轻量级进程(lightweight process)。如果在一个进程中同时运行了多个线程, 用来完成不同的工作, 则称之为多线程。
线程的特点:

  • 轻量级进程
  • 独立调度的基本单位
  • 可并发执行
  • 共享进程资源

4)、进程与线程的区别




































区别 进程 线程
根本区别 作为资源分配的最小单位 作为资源调度和执行的最小单位
开 销 每个进程都有独立的代码和数据空间(进程上下文), 进程间的切换会有较大的开销。 线程可以看成时轻量级的进程, 同一类线程共享代码和数据空间, 每个线程有独立的运行栈和程序计数器(PC), 线程切换的开销小。
所处环境 在操作系统中能同时运行多个任务(程序) 在同一应用程序中有多个顺序流同时执行
分配内存 系统在运行的时候会为每个进程分配不同的内存区域 除了CPU之外, 不会为线程分配内存(线程所使用的资源是它所属的进程的资源) , 线程组只能共享资源
包含关系 没有线程的进程是可以被看作单线程的, 如果一个进程内拥有多个线程, 则执行过程不是一条线的, 而是多条线(线程) 共同完成的。 线程是进程的一部分, 所以线程有的时候被称为是轻权进程或者轻量级进程。

5)、线程的生命周期

(json插队方法,属于对象 t1.join()表示必须等到t1线程执行完,才执行其他线程,t1执行的时候,其他线程都是属于阻塞状态)

1、新生状态 (一旦开启了新生状态,线程就有了自己的工作空间)

2、就绪状态(等待cpu调度,调用start方法)yield让出cpu的调度直接从运行状态转换到就绪状态、时间片用完由运行变就绪状态、jvm算法切换

3、运行状态(cpu调度到改线程)

4、阻塞状态(如,执行sleep方法,wait,或同步代码锁、join方法)

5、死亡状态(线程正常执行完毕,或者调用stop方法【不推荐,线程不安全】,通过标识符 使用terminate方法)


1)、创建线程的第一种方式:

继承Thread类,重写run方法

  1. public class MyThread extends Thread {
  2. @Override
  3. public void run() {
  4. System.out.println("当前线程的名字--->"+Thread.currentThread().getName());
  5. }
  6. public static void main(String[] args) {
  7. //创建4个线程
  8. MyThread t1 = new MyThread();
  9. MyThread t2 = new MyThread();
  10. MyThread t3 = new MyThread();
  11. MyThread t4 = new MyThread();
  12. //开启线程
  13. t1.start();
  14. t2.start();
  15. t3.start();
  16. t4.start();
  17. System.out.println("当前线程的名字--->"+Thread.currentThread().getName());
  18. }
  19. }

输出结果:

  1. 当前线程的名字--->main
  2. 当前线程的名字--->Thread-0
  3. 当前线程的名字--->Thread-1
  4. 当前线程的名字--->Thread-3
  5. 当前线程的名字--->Thread-2

这里线程的执行顺序并不是按照我们 执行start()的顺序,因为start()方法,并不是代表立即去执行线程,只不过是告诉cpu我可以被调度,至于它先执行哪个线程,要靠cpu去决定。(但是我们可以设置一个优先级,优先级高的显被执行的概率大,但是不是绝对的)

2)、创建线程的第二种方式:

实现Runnable接口。重写run方法

  1. public class MyRanableThread implements Runnable
  2. {
  3. @Override
  4. public void run() {
  5. System.out.println("当前线程的名字--->"+Thread.currentThread().getName());
  6. }
  7. public static void main(String[] args) {
  8. Thread t1 = new Thread(new MyRanableThread());
  9. t1.start();
  10. new Thread(new MyRanableThread()).start();
  11. new Thread(new MyRanableThread()).start();
  12. new Thread(new MyRanableThread()).start();
  13. }
  14. }

执行结果:

  1. 当前线程的名字--->Thread-2
  2. 当前线程的名字--->Thread-0
  3. 当前线程的名字--->Thread-1
  4. 当前线程的名字--->Thread-3

通过Thread的构造方法传入Runnable接口的实现类,然后执行start()方法,开启线程,相对于第一种方式,这里的Thread其实就是个静态代理对象。
那么两种的方式有什么区别呢
执行了start()方法之后,当线程被cpu调度之后,就会执行run()方法,进入Thread这个类,看一下run()方法的源码(部分):

  1. class Thread implements Runnable //thread类其实也是实现了Ruanable接口
  2. /* What will be run. */
  3. private Runnable target;
  4. @Override
  5. public void run() {
  6. if (target != null) {
  7. target.run();
  8. }
  9. }

原来当我们使用第一种方法 继承Thread类,重写run方法,在调用run方法的时候,必然就会调用子类重写的run方法,然后执行。但当我用第二种方法,也就是Thread构造传入Runnable接口的实现类之后,当我们要执行run方法,会先判断target是否为空,然后执行target.run(),也就是我们实现Runnable时候所重写的run方法。

发表评论

表情:
评论列表 (有 0 条评论,420人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java创建线方式

    线程的创建有两种方式,昨天学习过其中的一种: 创建一个类,继承自Java里的[Thread类][Thread],并重写run方法。 最后再创建自定义线程的对象,并调用sta

    相关 Java中创建线方式

    创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码,实现并行运行。 (实际上时根据操作系统的调度算法,分时间片运行,但由于cpu处理速度很高,宏观上看成时同时