• jdk1.8源码Thread与Runnable区别


    一、概念

    Thread实现了Runnable接口

     1 public class Thread implements Runnable {
     2     /* Make sure registerNatives is the first thing <clinit> does. */
     3     private static native void registerNatives();
     4     static {
     5         registerNatives();
     6     }
     7 
     8     private volatile char  name[];
     9     //表示线程的优先级(最大值为10,最小值为1,默认值为5),
    10     private int            priority;
    11   
    12 
    13     /* Whether or not the thread is a daemon thread. */
    14     //表示线程是否是守护线程,如果在main线程中创建了一个守护线程,
    15     //当main方法运行完毕之后,守护线程也会随着消亡。在JVM中,垃圾收集器线程就是守护线程。
    16     private boolean     daemon = false;
    17 
    18 
    19     /* What will be run. */
    20     //表示要执行的任务。
    21     private Runnable target;
    22    。。。。。。    
    23 }

    二、创建,启动线程的方法有两种:

    1,继承Thread

     1 class PrimeThread extends Thread {
     2      long minPrime;
     3      PrimeThread(long minPrime) {
     4          this.minPrime = minPrime;
     5      }
     6 
     7      public void run() {
     8          // compute primes larger than minPrime
     9           . . .
    10      }
    11  }
    12 
    13  PrimeThread p = new PrimeThread(143);
    14  p.start();

    2,实现Runnable 

     1 class PrimeRun implements Runnable {
     2  long minPrime;
     3  PrimeRun(long minPrime) {
     4      this.minPrime = minPrime;
     5  }
     6 
     7  public void run() {
     8      // compute primes larger than minPrime
     9       . . .
    10  }
    11 }
    12 
    13 
    14 PrimeRun p = new PrimeRun(143);
    15 new Thread(p).start();

    3,分析

    但都调用thread的start()启动线程,API的注解是:

    Causes this thread to begin execution; the Java Virtual Machine calls the <code>run</code> method of this thread.(使该线程开始执行;Java 虚拟机调用该线程的 run 方法。)

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

    而thread的run()方法只是一个普通方法而已,API的注解是:

    If this thread was constructed using a separate <code>Runnable</code> run object, then that <code>Runnable</code> object's <code>run</code> method is called;otherwise, this method does nothing and returns.(如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。)

    如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

     1 public class ThreadTest extends Thread{
     2 
     3     @Override
     4     public void run() {
     5         System.out.println("Thread Start !");
     6     }
     7 
     8     public static void main(String[] args) {
     9         ThreadTest threadTest = new ThreadTest();
    10         threadTest.start();
    11         System.out.println("不用等待!");
    12     }
    13 }

    结果:

    1 不用等待!
    2 Thread Start !
     1 public class ThreadTest extends Thread{
     2 
     3     @Override
     4     public void run() {
     5         System.out.println("Thread Start !");
     6     }
     7 
     8     public static void main(String[] args) {
     9         ThreadTest threadTest = new ThreadTest();
    10         threadTest.run();
    11         System.out.println("不用等待!");
    12     }
    13 }

    结果:

    1 Thread Start !
    2 不用等待!

     参考博文链接:  https://www.cnblogs.com/renhui/p/6066750.html

    三、关于卖票的问题:

    1,extends Thread

     1 public class MyThread extends Thread {
     2     private int tickets = 10;
     3     @Override
     4     public void run() {
     5 
     6         for (int i = 0; i <= 100; i++) {
     7             if(tickets>0){
     8                 System.out.println(Thread.currentThread().getName()+"--卖出票:" + tickets--);
     9             }
    10         }
    11     }
    12     public static void main(String[] args) {
    13         MyThread thread1 = new MyThread();
    14         MyThread thread2 = new MyThread();
    15         MyThread thread3 = new MyThread();
    16 
    17         thread1.start();
    18         thread2.start();
    19         thread3.start();
    20     }
    21 }

    结果:

     1 Thread-0--卖出票:10
     2 Thread-2--卖出票:10
     3 Thread-2--卖出票:9
     4 Thread-2--卖出票:8
     5 Thread-2--卖出票:7
     6 Thread-2--卖出票:6
     7 Thread-1--卖出票:10
     8 Thread-1--卖出票:9
     9 Thread-2--卖出票:5
    10 Thread-0--卖出票:9
    11 Thread-0--卖出票:8
    12 Thread-0--卖出票:7
    13 Thread-0--卖出票:6
    14 Thread-0--卖出票:5
    15 Thread-0--卖出票:4
    16 Thread-0--卖出票:3
    17 Thread-0--卖出票:2
    18 Thread-0--卖出票:1
    19 Thread-2--卖出票:4
    20 Thread-1--卖出票:8
    21 Thread-2--卖出票:3
    22 Thread-1--卖出票:7
    23 Thread-2--卖出票:2
    24 Thread-1--卖出票:6
    25 Thread-2--卖出票:1
    26 Thread-1--卖出票:5
    27 Thread-1--卖出票:4
    28 Thread-1--卖出票:3
    29 Thread-1--卖出票:2
    30 Thread-1--卖出票:1

    问题:每个线程都独立,不共享资源,每个线程都卖出了10张票,总共卖出了30张。

    2,implements Runnable

     1 public class MyRunnable implements Runnable {
     2 
     3     private int tickets = 64100;
     4     @Override
     5     public void run() {
     6         for (int i = 0; i <= 64200; i++) {
     7             if(tickets>0){
     8                 System.out.println(Thread.currentThread().getName()+"--卖出票:"+ tickets-- );
     9             }
    10         }
    11     }
    12 
    13     public static void main(String[] args) {
    14         MyRunnable myRunnable = new MyRunnable();
    15         Thread thread1 = new Thread(myRunnable, "窗口一");
    16         Thread thread2 = new Thread(myRunnable, "窗口二");
    17         Thread thread3 = new Thread(myRunnable, "窗口三");
    18 
    19         thread1.start();
    20         thread2.start();
    21         thread3.start();
    22     }
    23 }

    问题:每个线程共享了对象myRunnable的资源,但是当tickets足够大的时候就会出现一张票被卖出去多次的问题,原因是:读取共享变量tickets和减一这两个动作是原子操作,但这两个动作不可能用一条指令完成,一旦在这两个动作之间发生线程的切换,同一个值就会被读取2次,从而发生错误!

    解决方案就是在方法上加锁:

    1 synchronized (this) {
    2     if (tickets > 0) {
    3         System.out.println(Thread.currentThread().getName() + "--卖出票:" + tickets--);
    4     }
    5 }

     四、拓展

     关于Thread的详细源码剖析可参考https://www.cnblogs.com/dennyzhangdd/p/7280032.html

     关于Thread多次start一个线程报错:IllegalThreadStateException()

    ----------------------------------------------多做多解决多总结-----------------------------------

  • 相关阅读:
    10分钟学会SpringBoot入门
    单链表常见的4道笔试题(Java版)
    Java面试、跳槽必刷200+真面试题,让你披荆斩棘走进大厂
    金三银四JAVA面试总结:Java+并发+Spring+MySQL+分布式+Redis+算法+JVM等
    最新整理的spring面试题从基础到高级,干货满满
    面试阿里百分百问的Jvm,别问有没有必要学,真的很有必要朋友
    面试官:你们前后端分离的接口规范是什么?
    “金九银十”已过,总结我的天猫、蚂蚁、头条面试经历(Java岗)
    350道面试题分享,拿下京东offer工资double
    2019大厂Java岗面试题全曝光,刷完这1020道,金三银四大厂等你
  • 原文地址:https://www.cnblogs.com/sqy123/p/9780110.html
Copyright © 2020-2023  润新知