一、概念

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

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

转载于:https://www.cnblogs.com/sqy123/p/9780110.html

jdk1.8源码Thread与Runnable区别相关推荐

  1. 【JUC】JDK1.8源码分析之ArrayBlockingQueue(三)

    一.前言 在完成Map下的并发集合后,现在来分析ArrayBlockingQueue,ArrayBlockingQueue可以用作一个阻塞型队列,支持多任务并发操作,有了之前看源码的积累,再看Arra ...

  2. JDK1.8源码分析:可重入锁ReentrantLock和Condition的实现原理

    synchronized的用法和实现原理 synchronized实现线程同步的用法和实现原理 不足 synchronized在线程同步的使用方面,优点是使用简单,可以自动加锁和解锁,但是也存在一些不 ...

  3. 【集合框架】JDK1.8源码分析之HashMap(一)

    转载自  [集合框架]JDK1.8源码分析之HashMap(一) 一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大 ...

  4. 【集合框架】JDK1.8源码分析HashSet LinkedHashSet(八)

    一.前言 分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet ...

  5. JDK1.1源码学习之官方文档与代码结构

    浩哥带你学习JDK1.1源码--第2天 1. 阅读源码那点事 2. JDK 1.1.8源码结构 1. 阅读源码那点事 在上一篇的文章中,进入Java官网的档案袋里面,可以看到文档有两个下载链接:一个日 ...

  6. JDK1.8源码(三)——java.lang.String 类

    String 类也是java.lang 包下的一个类,算是日常编码中最常用的一个类了,那么本篇博客就来详细的介绍 String 类. 1.String 类的定义 public final class ...

  7. 【JUC】JDK1.8源码分析之ConcurrentLinkedQueue(五)

    一.前言 接着前面的分析,接下来分析ConcurrentLinkedQueue,ConcurerntLinkedQueue一个基于链接节点的无界线程安全队列.此队列按照 FIFO(先进先出)原则对元素 ...

  8. 今天读了JDK1.8源码,知道了并行迭代器Spliterator

    在JDK1.8的ArrayList里面偶然看到了这个内部类,同时对比了1.7的版本,发现1.7并没有这后面的东西, 随着好奇心,就搜了一下下,发现很有意思~  也查了一些资料,如下总结: Splite ...

  9. 【JUC】JDK1.8源码分析之ConcurrentHashMap

    一.前言 最近几天忙着做点别的东西,今天终于有时间分析源码了,看源码感觉很爽,并且发现ConcurrentHashMap在JDK1.8版本与之前的版本在并发控制上存在很大的差别,很有必要进行认真的分析 ...

最新文章

  1. 微服务注册中心的选型和思考
  2. C语言中两种方式表示时间日期值time_t和struct tm类型的相互转换
  3. 两个有序数组的中位数(第k大的数)
  4. Django之中间件
  5. 基于组件的案例:购物车
  6. 8、REVOKE:删除用户权限
  7. mPaaS 客户端问题排查之突如其来的“白屏”等待
  8. ORA-00600: 内部错误代码,参数: [qctcte1], [0], [], [], [], [], [], []
  9. springboot通过url访问项目外的其他目录下的图片
  10. update empty content to text instance - where is B mode changed to D by frame
  11. python中test_在python中生成py.test测试
  12. java国王毒酒答案,换换脑子500桶酒国王用囚犯找毒酒答案-500桶酒其中1桶是毒酒找毒酒答案最新版【附公式详解】-东坡下载...
  13. hdu 1693 Eat the Trees 插头dp
  14. springBoot事物
  15. SCCM 2012 SP1系列(一)先决条件准备-1
  16. crossentropy java_示例CrossEntropyLoss用于pytorch中的3D语义分段
  17. 微信分销系统源码定制开发
  18. 代码检查技术Checkstyle与p3c调研
  19. bde oracle 商友的流程_BDE动态连接Oracle数据库
  20. (附源码)ssm基于WEB的房屋出租管理系统 毕业设计261620

热门文章

  1. openstack pike版本安装笔记8(Orchestration Server:heat组件,模板服务)
  2. 自己来实现一套IOC注解框架
  3. Apahce服务器配置非根目录的虚拟目录
  4. Puppet 部署tomcat
  5. ubuntu 10.04的git安装和使用
  6. 虚拟机上安装Linux时出现的问题及解决方法
  7. CDH ecosystem components
  8. 面试题:长方形个数计算
  9. Sharepoint2010 表单认证常见问题
  10. 再谈初学者关心的ssh应用方方面面