线程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( ...
- angularJS中$apply()方法详解
这篇文章主要介绍了angularJS中$apply()方法详解,需要的朋友可以参考下 对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的 ...
- Java构造和解析Json数据的两种方法详解二
在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Jso ...
- jQuery中 $.ajax()方法详解
$.ajax()方法详解 jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为Strin ...
- Java构造和解析Json数据的两种方法详解二——org.json
转自:http://www.cnblogs.com/lanxuezaipiao/archive/2013/05/24/3096437.html 在www.json.org上公布了很多JAVA下的jso ...
- MySQL服务器线程数的查看方法详解
本文实例讲述了MySQL服务器线程数的查看方法.分享给大家供大家参考,具体如下: mysql重启命令: ? 1 /etc/init.d/mysql restart MySQL服务器的线程数需要在一个合 ...
- python中常用模块详解二
log模块的讲解 Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适: logger提供了应用程序可以直接使用的接口API: handler将(logger创建的 ...
- Java多线程中join方法详解
join()方法用于让当前执行线程等待join线程执行结束.其实现原理是不停的检查join线程是否存活,如果join线程存活则让当前线程永远等待. join()方法部分实现细节 while(isAli ...
- Java中常见方法详解合集(方法的定义及语法结构)
Java的方法定义 1.方法的定义 方法是控制对象的动作行为方式与准则,在Java中方法位于类体下又有另一种含义. 普通的方法在类中称为"实例方法",因为方法的调用需要创建对象,而 ...
随机推荐
- Spring Cloud09: Config 配置中心
一.概述 什么是配置中心呢,在基于微服务的分布式系统中,每个业务模块都可以拆分成独立自主的服务,由多个请求来协助完成某个需求,那么在某一具体的业务场景中,某一个请求需要调用多个服务来完成,那么就存在一 ...
- Java静态方法和实例方法的区别以及this的用法
Java静态方法和实例方法 相同之处:都能接收传过来的参数,都能返回参数. 不同之处:有static就是静态方法,静态方法在另外一个类里面,不用new这个静态方法所在的类,也能直接访问这个方法,比较方 ...
- 【NX二次开发】大开眼界,DLL还可以这么调!
NX二次开发应用程序有交互式.批处理和远程3中模式.交互模式的应用程序(.dll)在NX界面环境下运行.dll以动态链接库的方式被加载到NX的进程空间中.dll可以通过下列几种方式执行. 1.直接激活 ...
- 【Azure Redis 缓存】由Azure Redis是否可以自定义密码而引申出Azure PaaS的Redis服务是否可以和自建的Redis进行主从配置呢?
问题描述 在自建的Redis服务中,可以通过 config set requirepass <Password> 设置Redis的登录密码,然后使用auth 命令输入密码.操作命令如下: ...
- golang 模板语法使不解析html标签及特殊字符
场景 有时候需要使用go的模板语法,比如说用go 去渲染html页面的时候,再比如说用go的模板搞代码生成的时候.这时候可能会遇到一个麻烦,不想转译的特殊字符被转译了. 我遇到的情况是写代码生成器的时 ...
- python安装、卸载包的方法
anaconda包管理器 conda命令[1] 环境管理 conda info -e # 查看当前已安装的环境 conda create -n py27 python=2.7 # 添加2.7版本的Py ...
- Kubernetes之Ingress
在Service篇里面介绍了像集群外部的客户端公开服务的两种方法,还有另一种方法---创建Ingress资源. 定义Ingress (名词)-进入或进入的行为;进入的权利;进入的手段或地点;入口. 接 ...
- .net core 支付宝,微信支付 一
源码: https://github.com/aspros-luo/Qwerty.Payment/tree/develop 支付宝支付:参考支付宝sdk及文档,https://docs.open.al ...
- Harbor镜像仓库
Harbor镜像仓库 作者 刘畅 时间 2020-7-11 微信 目录 1.下载离线安装包 1 2.安装docker 1 3.安装docker-compose 2 4.自签TLS证书 2 4.1.创建 ...
- uniapp 微信小程序 打开文件
uni.downloadFile({ url: item.url, success: (res) => { if (res.statusCode === 200) { uni.openDocum ...