jdk1.8源码Thread与Runnable区别
一、概念
Thread实现了Runnable接口
public class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
private volatile char name[];
//表示线程的优先级(最大值为10,最小值为1,默认值为5),
private int priority;
/* Whether or not the thread is a daemon thread. */
//表示线程是否是守护线程,如果在main线程中创建了一个守护线程,
//当main方法运行完毕之后,守护线程也会随着消亡。在JVM中,垃圾收集器线程就是守护线程。
private boolean daemon = false;
/* What will be run. */
//表示要执行的任务。
private Runnable target;
。。。。。。
}
二、创建,启动线程的方法有两种:
1,继承Thread
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeThread p = new PrimeThread(143);
p.start();
2,实现Runnable
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeRun p = new PrimeRun(143);
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方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
public class ThreadTest extends Thread{
@Override
public void run() {
System.out.println("Thread Start !");
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
System.out.println("不用等待!");
}
}
结果:
不用等待!
Thread Start !
public class ThreadTest extends Thread{
@Override
public void run() {
System.out.println("Thread Start !");
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
threadTest.run();
System.out.println("不用等待!");
}
}
结果:
Thread Start !
不用等待!
参考博文链接: https://www.cnblogs.com/renhui/p/6066750.html
三、关于卖票的问题:
1,extends Thread
public class MyThread extends Thread {
private int tickets = 10;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"--卖出票:" + tickets--);
}
}
}
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
MyThread thread3 = new MyThread();
thread1.start();
thread2.start();
thread3.start();
}
}
结果:
Thread-0--卖出票:10
Thread-2--卖出票:10
Thread-2--卖出票:9
Thread-2--卖出票:8
Thread-2--卖出票:7
Thread-2--卖出票:6
Thread-1--卖出票:10
Thread-1--卖出票:9
Thread-2--卖出票:5
Thread-0--卖出票:9
Thread-0--卖出票:8
Thread-0--卖出票:7
Thread-0--卖出票:6
Thread-0--卖出票:5
Thread-0--卖出票:4
Thread-0--卖出票:3
Thread-0--卖出票:2
Thread-0--卖出票:1
Thread-2--卖出票:4
Thread-1--卖出票:8
Thread-2--卖出票:3
Thread-1--卖出票:7
Thread-2--卖出票:2
Thread-1--卖出票:6
Thread-2--卖出票:1
Thread-1--卖出票:5
Thread-1--卖出票:4
Thread-1--卖出票:3
Thread-1--卖出票:2
Thread-1--卖出票:1
问题:每个线程都独立,不共享资源,每个线程都卖出了10张票,总共卖出了30张。
2,implements Runnable
public class MyRunnable implements Runnable {
private int tickets = 64100;
@Override
public void run() {
for (int i = 0; i <= 64200; i++) {
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"--卖出票:"+ tickets-- );
}
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable, "窗口一");
Thread thread2 = new Thread(myRunnable, "窗口二");
Thread thread3 = new Thread(myRunnable, "窗口三");
thread1.start();
thread2.start();
thread3.start();
}
}
问题:每个线程共享了对象myRunnable的资源,但是当tickets足够大的时候就会出现一张票被卖出去多次的问题,原因是:读取共享变量tickets和减一这两个动作是原子操作,但这两个动作不可能用一条指令完成,一旦在这两个动作之间发生线程的切换,同一个值就会被读取2次,从而发生错误!
解决方案就是在方法上加锁:
synchronized (this) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "--卖出票:" + tickets--);
}
}
四、拓展
关于Thread的详细源码剖析可参考:https://www.cnblogs.com/dennyzhangdd/p/7280032.html
关于Thread多次start一个线程报错:IllegalThreadStateException()
----------------------------------------------多做多解决多总结-----------------------------------
jdk1.8源码Thread与Runnable区别的更多相关文章
- java多线程机制中的Thread和Runnable()区别
1.java语言使用Thread类及其子类对象来表示线程,新建的一个线程声明周期中经历 新建.(声明一个线程,此时他已经有了相应的内存空间和其他资源),运行(线程创建之久就据用了运行的条件,一旦轮到使 ...
- 【1】【JUC】JDK1.8源码分析之ArrayBlockingQueue,LinkedBlockingQueue
概要: ArrayBlockingQueue的内部是通过一个可重入锁ReentrantLock和两个Condition条件对象来实现阻塞 注意这两个Condition即ReentrantLock的Co ...
- 【1】【JUC】JDK1.8源码分析之ReentrantLock
概要: ReentrantLock类内部总共存在Sync.NonfairSync.FairSync三个类,NonfairSync与FairSync类继承自Sync类,Sync类继承自AbstractQ ...
- JDK1.8源码学习-Object
JDK1.8源码学习-Object 目录 一.方法简介 1.一个本地方法,主要作用是将本地方法注册到虚拟机中. private static native void registerNatives() ...
- 【JUC】JDK1.8源码分析之ArrayBlockingQueue(三)
一.前言 在完成Map下的并发集合后,现在来分析ArrayBlockingQueue,ArrayBlockingQueue可以用作一个阻塞型队列,支持多任务并发操作,有了之前看源码的积累,再看Arra ...
- JDK1.8源码学习-LinkedList
JDK1.8源码学习-LinkedList 目录 一.LinkedList简介 LinkedList是一个继承于AbstractSequentialList的双向链表,是可以在任意位置进行插入和移除操 ...
- JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类
JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类 Unsafe Java中无法直接操作一块内存区域,不能像C++中那样可以自己申请内存 ...
- 【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)
一.前言 分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet ...
- JDK1.8源码阅读系列之三:Vector
本篇随笔主要描述的是我阅读 Vector 源码期间的对于 Vector 的一些实现上的个人理解,用于个人备忘,有不对的地方,请指出- 先来看一下 Vector 的继承图: 可以看出,Vector 的直 ...
随机推荐
- Linux内核分析(第六周)
进程的控制与创建 一.进程的描述 1.操作系统内核的三大功能:进程管理(核心),内存管理,文件系统: 2.状态: fork() task_zombit(终止) task_running(就绪:但是没有 ...
- 第二阶段站立会议alpha版总结
一.会议过程 在完成第二次冲刺后,Alpha版本最终发布,我们对校园二手交易平台开发过程及产品存在的问题进行了激烈讨论.进行了我们的团队总结会议,会议中每个人先发表了个人对Alpha版开发过程中存在的 ...
- (第三周)c#程序理解
阅读下面程序,请回答如下问题: 问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间 ...
- sleep,yield,join,notify,wait,notifyAll区别
1. Thread.sleep(long) 和Thread.yield()都是Thread类的静态方法,在调用的时候都是Thread.sleep(long)/Thread.yield()的方式进行调 ...
- oralce下载
oracle的官网网址:oracle.com 打开之后选择中文 然后在页面的下方找到下载和试用链接 点击进入,选择数据库下载,在页面中找到如下部分点击进入即可下载对应版本的oracle
- bzoj 1012: [JSOI2008]最大数maxnumber (线段树)
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 13081 Solved: 5654[Subm ...
- Spring Shell打Jar包时需要注意的地方
Spring-Shell打Jar包时需要注意的地方: 1.Main-Class spring-shell项目打Jar包的一个必要条件就是,指定Main-Class为org.springframew ...
- 自学huawei之路-AC6005-8AP添加授权码
返回自学Huawei之路 自学huawei之路-AC6005-8AP添加授权码
- 【字符串算法1】 再谈字符串Hash(优雅的暴力)
[字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述 [字符串算法1] 字符串Hash 老版原文: RK哈希(Rabin_Ka ...
- 4.Kali 1.0 / 2.0 安装中文输入法(谷歌pinyin + 其他)
搜狗输入法安装可以参考这个:http://www.cnblogs.com/dunitian/p/6662374.html 1.kali默认是没有中午输入法的,需要自己安装一下 2.首先我们先获取roo ...