(二)线程Thread中的方法详解
1、start()
- start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果。通过start()方法产生得到结论,先看下代码:
/**
* @author zs
* @date 2019/9/20 10:13
*/
public class MyTicketThread extends Thread {
private int ticket=5;//仅剩五张票
public MyTicketThread(String threadName) {
super(threadName);//调用父类的带参构造方法
} @Override
public void run() { // TODO Auto-generated method stub
for(int i=0;i<100;i++){
synchronized (this) {
if(ticket>0){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖第"
+ (ticket--) + "张票");
}
}
}
}
}
/**
* @author zs
* @date 2019/9/20 10:14
*/
public class Test {
public static void main(String[] args) {
//4个窗口
MyTicketThread t1=new MyTicketThread("A窗口");
MyTicketThread t2=new MyTicketThread("B窗口");
MyTicketThread t3=new MyTicketThread("C窗口");
MyTicketThread t4=new MyTicketThread("D窗口");
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行结果:
B窗口卖第5张票
C窗口卖第5张票
D窗口卖第5张票
A窗口卖第5张票
D窗口卖第4张票
A窗口卖第4张票
B窗口卖第4张票
C窗口卖第4张票
D窗口卖第3张票
A窗口卖第3张票
...
- 解释:可以看出,线程执行的先后顺序,是不确定的。
2、currentThread()
currentThread()方法返回的是对当前正在执行线程对象的引用。
在线程类中,有两种方式,一定要理解这两种方式的区别:
(1)this.XXX()
这种调用方式表示的线程是线程实例本身
(2)Thread.currentThread.XXX()或Thread.XXX()
上面两种写法是一样的意思。这种调用方式表示的线程是正在执行Thread.currentThread.XXX()所在代码块的线程
下面通过看一个重要的例子,然后得出结论:

public class MyThread04 extends Thread
{
static
{
System.out.println("静态块的打印:" +
Thread.currentThread().getName());
} public MyThread04()
{
System.out.println("构造方法的打印:" +
Thread.currentThread().getName());
} public void run()
{
System.out.println("run()方法的打印:" +
Thread.currentThread().getName());
}
}

public static void main(String[] args)
{
MyThread04 mt = new MyThread04();
mt.start();
}
看一下运行结果:
静态块的打印:main
构造方法的打印:main
run()方法的打印:Thread-0
这个例子说明了,线程类的构造方法、静态块是被main线程调用的,而线程类的run()方法才是应用线程自己调用的。在这个例子的基础上,再深入:

public class MyThread05 extends Thread
{
public MyThread05()
{
System.out.println("MyThread5----->Begin");
System.out.println("Thread.currentThread().getName()----->" +
Thread.currentThread().getName());
System.out.println("this.getName()----->" + this.getName());
System.out.println("MyThread5----->end");
} public void run()
{
System.out.println("run----->Begin");
System.out.println("Thread.currentThread().getName()----->" +
Thread.currentThread().getName());
System.out.println("this.getName()----->" + this.getName());
System.out.println("run----->end");
}
}

public static void main(String[] args)
{
MyThread05 mt5 = new MyThread05();
mt5.start();
}
看一下运行结果:

MyThread5----->Begin
Thread.currentThread().getName()----->main
this.getName()----->Thread-0
MyThread5----->end
run----->Begin
Thread.currentThread().getName()----->Thread-0
this.getName()----->Thread-0
run----->end

可以看出:当前执行的Thread未必就是Thread本身。从这个例子就能看出来:
(1)执行MyThread05构造方法是main,当前线程却是Thread-0
(2)执行run()方法的Thread-0,当前线程也是Thread-0,说明run()方法就是被线程实例去执行的
所以,再强调一下,未必在MyThread05里调用Thread.currentThread()返回回来的线程对象的引用就是MyThread05。
3、sleep(long millis)
sleep(long millis)方法的作用是在指定的毫秒内让当前"正在执行的线程"休眠(暂停执行)。这个"正在执行的线程"是关键,指的是Thread.currentThread()返回的线程。根据JDK API的说法,"该线程不丢失任何监视器的所属权",简单说就是sleep代码上下文如果被加锁了,锁依然在,但是CPU资源会让出给其他线程。看一下例子:

public class MyThread07 extends Thread
{
public void run()
{
try
{
System.out.println("run threadName = " +
this.getName() + " begin");
Thread.sleep(2000);
System.out.println("run threadName = " +
this.getName() + " end");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}


public static void main(String[] args)
{
MyThread07 mt = new MyThread07();
System.out.println("begin = " + System.currentTimeMillis());
mt.start();
System.out.println("end = " + System.currentTimeMillis());
}

看一下运行结果:
begin = 1443694780609
end = 1443694780609
run threadName = Thread-0 begin
run threadName = Thread-0 end
当然,因为打印结果是静态的,所以只能看出异步执行的效果,看不出sleep(long millis)方法执行的效果。实际上第3句打出2秒后打出第4句,这和run()方法里面的sleep(2000)是对应的
4、yield()
暂停当前执行的线程对象,并执行其他线程。这个暂停是会放弃CPU资源的,并且放弃CPU的时间不确定,有可能刚放弃,就获得CPU资源了,也有可能放弃好一会儿,才会被CPU执行。看一下例子:

public class MyThread08 extends Thread
{
public void run()
{
long beginTime = System.currentTimeMillis();
int count = 0;
for (int i = 0; i < 50000000; i++)
{
Thread.yield();
count = count + i + 1;
}
long endTime = System.currentTimeMillis();
System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
}
}

public static void main(String[] args)
{
MyThread08 mt = new MyThread08();
mt.start();
}
看一下运行结果:

用时:3264毫秒!
用时:3299毫秒!
用时:3232毫秒!
用时:3256毫秒!
用时:3283毫秒!
用时:3504毫秒!
用时:3378毫秒!

看到,每次执行的用时都不一样,证明了yield()方法放弃CPU的时间并不确定。
5、注意
1、sleep()和wait()方法的区别,三点:
- sleep()是Thread中的方法,线程休眠;wait()是Object中的方法,线程等待;
- 都导致线程的阻塞;
- sleep()对对象所持有的锁不释放,wait()释放所持有的锁;
2、Java中Wait、Sleep和Yield方法的区别
- wait()是Object的方法,用于线程间的通信,线程等待,进入阻塞状态,会释放锁;
- sleep是Thread的静态方法,调用该方法,令当前线程休眠,进入阻塞状态,不会释放锁;
- yield和sleep的主要是,yield方法会临时暂停当前正在执行的线程,来让有同样优先级的正在等待的线程有机会执行。如果没有正在等待的线程,或者所有正在等待的线程的优先级都比较低,那么该线程会继续运行。执行了yield方法的线程什么时候会继续运行由线程调度器来决定,不同的厂商可能有不同的行为。yield方法不保证当前的线程会暂停或者停止,但是可以保证当前线程在调用yield方法时会放弃CPU。
(二)线程Thread中的方法详解的更多相关文章
- 线程Thread中的方法详解(二)
1.start() start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果.通过start( ...
- JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解
二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...
- angularJS中$apply()方法详解
这篇文章主要介绍了angularJS中$apply()方法详解,需要的朋友可以参考下 对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的 ...
- jQuery中 $.ajax()方法详解
$.ajax()方法详解 jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为Strin ...
- MySQL服务器线程数的查看方法详解
本文实例讲述了MySQL服务器线程数的查看方法.分享给大家供大家参考,具体如下: mysql重启命令: ? 1 /etc/init.d/mysql restart MySQL服务器的线程数需要在一个合 ...
- Java多线程中join方法详解
join()方法用于让当前执行线程等待join线程执行结束.其实现原理是不停的检查join线程是否存活,如果join线程存活则让当前线程永远等待. join()方法部分实现细节 while(isAli ...
- Java中常见方法详解合集(方法的定义及语法结构)
Java的方法定义 1.方法的定义 方法是控制对象的动作行为方式与准则,在Java中方法位于类体下又有另一种含义. 普通的方法在类中称为"实例方法",因为方法的调用需要创建对象,而 ...
- boost库中sleep方法详解
博客转载自:https://blog.csdn.net/huang_xw/article/details/8453506 boost库中sleep有两个方法: 1. 这个方法只能在线程中用, 在主线程 ...
- JavaScript中getBoundingClientRect()方法详解
获取浏览器滚动的高度: scrollTop=document.documentElement.scrollTop || document.body.scrollTop getBoundingClien ...
随机推荐
- java_guide_类加载器
类加载器总结 JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader ...
- String、StringBuilder、StringBuffer的爱恨情仇
第三阶段 JAVA常见对象的学习 StringBuffer和StringBuilder类 (一) StringBuffer类的概述 (1) 基本概述 下文以StringBuffer为例 前面我们用字符 ...
- [转帖]linux命令dd
linux命令dd dd 是diskdump 的含义 之前学习过 总是记不住 用的还是少. http://embeddedlinux.org.cn/emb-linux/entry-level/20 ...
- LeetCode 第 167 场周赛
1290.二进制链表转整数 1291.顺次数 1292.元素和小于等于阈值的正方形的最大边长 1293.网格中的最短路径 1290.二进制链表转整数 1290.二进制链表转整数 给你一个单链表的引用结 ...
- 【AtCoder】ARC060
ARC060 C - 高橋君とカード / Tak and Cards 每个数减去A,然后转移N次,每次选或不选,最后是和为0的时候的方案数,负数可以通过把所有数右移2500做到 #include &l ...
- Python实现二叉树的非递归先序遍历
思路: 1. 使用列表保存结果: 2. 使用栈(列表实现)存储结点: 3. 当根结点存在,保存结果,根结点入栈: 4. 将根结点指向左子树: 5. 根结点不存在,栈顶元素出栈,并将根结点指向栈顶元素的 ...
- JVM学习(一)Java虚拟机运行时数据区域
一.Java内存区域 1.运行时数据区域 根据<Java 虚拟机规范(Java SE 7 版)>规定,Java 虚拟机所管理的内存包括以下几个运行时数据区域: 1.1 程序计数器 程序计数 ...
- P2279 消防局的设立 (树形DP or 贪心)
(点击此处查看原题) 树形DP写法 看到这个题的要求,很容易相到这是一个树形DP的问题,但是dp数组应该如何设计并转移才是关键 dp[i][0]代表当前结点可以向上覆盖2层,自身一定被覆盖dp[i][ ...
- eventFlow 系列 <一> 入门
var exampleId = ExampleId.New; var commandBus = resolver.Resolve<ICommandBus>(); ,) var execut ...
- CodeFirst与EntityFramework【续】
3. 实现一对一的关系.在介绍一对多关系和多对多关系时,大家应该已经注意到了只要存在依赖关系的两个类的定义中包含对方的实例或实例的集合,Entity Framework Code First会自 ...