线程之sleep(),wait(),yield(),join()等等的方法的区别
操作线程的常用方法大体上有sleep(),join(),yield()(让位),wait(),notify(),notifyAll(),关键字synchronized等等。
由于这些方法功能有些相似,所以有时候会混乱,我们就需要了解它们的具体的原理,以及通过自己写的具体的例子去巩固,加深印象
sleep(),yield()方法的区别:
sleep()和yield()都是Thread类中的静态方法,都会使得当前处于运行状态的线程放弃CPU,但是两者的区别还是有比较大的:
1:sleep使当前线程(即调用sleep方法的线程暂停一段时间),给其它的线程运行的机会,而且是不考虑其它线程的优先级的,而且不释放资源锁,也就是说如果有synchronized同步块
,其它线程仍然是不能访问共享数据的;yeild只会让位给优先级一样或者比它优先级高的线程,而且不能由用户指定暂停多长时间
2:当线程执行了sleep方法之后,线程将转入到睡眠状态,直到时间结束,而执行yield方法,直接转入到就绪状态。这些对线程的生命周期(以后的博客会详细说明)会造成影响的。
3:sleep方法需要抛出或者捕获异常,因为线程在睡眠中可能被打断,而yield方法则没异常。
测试小程序:
public class Test7 {
public static void main(String[] args) {
MyTask4 mt1=new MyTask4();
MyTask4 mt2=new MyTask4();
Thread t1=new Thread(mt1);
t1.setName("线程一");
Thread t2=new Thread(mt2);
t2.setName("线程二");
t1.setPriority(10);
t2.setPriority(1);
t1.start();
t2.start();
}
}
class MyTask4 implements Runnable{
@Override
public void run() {
//取出当前线程
Thread t=Thread.currentThread();
if("线程一".equals(t.getName())){
try {
//Thread.yield();
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int i = 0; i < 10; i++) {
System.out.println(t.getName()+":"+i);
}
}
}
运行结果如下:
join方法则是用于等待其他线程结束,当前运行的线程可以调用另外一个线程的join()方法,当前的进程状态将转入到挂起状态,知道另外一线程运行结束,该线程才继续运行。
注意:该方法也要抛出或者捕获异常。
测试小程序:
/* join方法用于等待其他线程结束
*/
public class Test8 {
public static void main(String[] args) throws InterruptedException {
MyTask5 mt=new MyTask5();
Thread t=new Thread(mt);
t.setName("新线程");
System.out.println(t.isAlive());
t.start();
System.out.println(t.isAlive());
t.join();//等待t线程运行完再运行主线程
System.out.println("主线程");
System.out.println(t.isAlive());
}
}
class MyTask5 implements Runnable{
@Override
public void run() {
int i=0;
while((i++<10)){
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
运行的结果如下:
synchronized关键字:
该关键字用于保护共享的数据,当然前提条件是要分清那个数据是共享的数据,每个对象都有一个锁标志,当一个线程访问到该对象,被Synchronized修饰的数据将被"上锁",阻止其他线程访问。
当前线程访问完这部分数据后释放锁标志,其他线程就可以访问了。但是如果同步块过多,就相当于单线程了,所以这里要灵活运用。
wait(),notify(),notifyAll()
这3个方法都是Object类下的方法,而且结合使用。
这3个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用,如果不放在synchronized中,则会报出java.lang.IllegalMonitorStateException异常。
synchronized关键字用于保护共享数据阻止其他线程对共享数据的存取,但是这样程序的流程就很不灵活了,如何才能在当前线程还没退出synchronized数据块时让其他线程也有机会
访问共享数据 呢?
此时就用这三个方法来灵活控制。
wait() 方法使当前线程暂停执行并释放对象锁标示,释放锁这点非常的重要,让其他线程可以进入synchronized数据块,当前线程被放入对象等待池中。当调用notify()方法后,
将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,注意
只有锁标志等待池中线程能够获取锁标志;如果锁标志等待池中没有线程,则 notify()不起作用。
notifyAll()则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。
wait() 在其他线程调用此对象的 notify() 方法或者 notifyAll()方法前,导致当前线程等待。
wait(long timeout)在其他线程调用此对象的notify() 方法 或者 notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。
wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其他shnchronized数据可被别的线程使用。
wait()h 和notify()因为会对对象的“锁标志”进行操作,所以他们必需在Synchronized函数或者 synchronized block 中进行调用。如果在non-synchronized 函数
或 non-synchronized block 中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
测试小程序:
public class Test6 {
public static void main(String[] args) {
Fushikang fushikang=new Fushikang();
Producer p=new Producer(fushikang);
Producer p2=new Producer(fushikang);
Sale s=new Sale(fushikang);
Thread t1=new Thread(p);
Thread t2=new Thread(p2);
Thread t3=new Thread(s);
t1.setName("生产一部");
t2.setName("生产二部");
t3.setName("销售一部");
t1.start();
t2.start();
t3.start();
}
}
class Producer implements Runnable{
//生产和消费都是同一资源
private Fushikang fushikang;
public Producer(Fushikang fushikang){
this.fushikang=fushikang;
}
@Override
public void run() {
for(int i=0;i<10;i++){
Iphone iphone=new Iphone(i);
fushikang.product(iphone);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"生产了"+iphone.getId()+"号手机");
}
}
}
class Sale implements Runnable{
private Fushikang fushikang;
public Sale(Fushikang fushikang){
this.fushikang=fushikang;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
Iphone iphone=fushikang.sale();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"销售了"+iphone.getId()+"号手机");
}
}
}
class Fushikang{
private int index=0;
private Iphone[] warehouse=new Iphone[10];
public synchronized void product(Iphone iphone){
//入库iphone到warehouse
while(index==warehouse.length){
//让当前的线程停下,直到被sale唤醒
try {
this.wait(); //wait方法必须放在synchronized块中
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notifyAll();
warehouse[index]=iphone;
index++;
}
public synchronized Iphone sale(){
while(index==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();//唤醒多个
index--;
return warehouse[index];
}
}
class Iphone{
private int id;
public Iphone(int id){
this.id=id;
}
public int getId(){
return id;
}
public void setId(int id){
this.id=id;
}
}
线程之sleep(),wait(),yield(),join()等等的方法的区别的更多相关文章
- 【CompletableFuture】CompletableFuture中join()和get()方法的区别
一.相同点: join()和get()方法都是用来获取CompletableFuture异步之后的返回值 二.区别: 1.join()方法抛出的是uncheck异常(即未经检查的异常),不会强制开发者 ...
- 【原】iOS多线程之NSThread、NSOperationQueue、NSObject和GCD的区别
区别: Thread: 是这几种方式里面相对轻量级的,但也是使用起来最负责的,你需要自己管理thread的生命周期,线程之间的同步.线程共享同一应用程序的部分内存空间, 它们拥有对数据相同的访问权限. ...
- java多线程之yield,join,wait,sleep的区别
Java多线程之yield,join,wait,sleep的区别 Java多线程中,经常会遇到yield,join,wait和sleep方法.容易混淆他们的功能及作用.自己仔细研究了下,他们主要的区别 ...
- 多线程之join方法
join方法的功能就是使异步执行的线程变成同步执行.也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方 ...
- Java基础-进程与线程之Thread类详解
Java基础-进程与线程之Thread类详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程与线程的区别 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 ...
- JAVA多线程之wait/notify
本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...
- Java线程之 InterruptedException 异常
Java线程之 InterruptedException 异常 当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法. 抛 ...
- 第十五章、线程之queue模块的各种队列
目录 第十五章.线程之queue模块的各种队列 一.Queue 二.LifoQueue堆栈 三.PriorityQueue优先级队列 第十五章.线程之queue模块的各种队列 一.Queue impo ...
- iOS多线程之8.NSOPeration的其他用法
本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...
随机推荐
- CQRS之旅——旅程2(分解领域)
旅程2:分解领域 设计停靠站点 "没有石头就没有拱门" --马可波罗 在本章中,我们将对Contoso会议管理系统进行一个高层次的概述.这将帮助您理解应用程序的结构.集成点以及应用 ...
- Oracle视图,索引,序列
什么是视图[View] (1)视图是一种虚表 (2)视图建立在已有表的基础上, 视图赖以建立的这些表称为基表(3)向视图提供数据内容的语句为 SELECT 语句,可以将视图理解为存储起来的 SELEC ...
- Python3基础(3)集合、文件操作、字符转编码、函数、全局/局部变量、递归、函数式编程、高阶函数
---------------个人学习笔记--------------- ----------------本文作者吴疆-------------- ------点击此处链接至博客园原文------ 1 ...
- HDU 5452——Minimum Cut——————【树链剖分+差分前缀和】ACdream 1429——Diversion——————【树链剖分】
Minimum Cut Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)Tota ...
- Kotlin lateinit 和 by lazy 的区别
1.lazy{} 只能用在val类型, lateinit 只能用在var类型 2.lateinit不能用在可空的属性上和java的基本类型上 3.lateinit可以在任何位置初始化并且可以初始化多次 ...
- cmd对其他盘符进行操作
一般我们打开cmd命令时,会出现如下界面: 现在,我想要对g盘进行操作,则输入 --> g:,然后回车,如图: 可以查看一下g盘下的所有子目录,输入 --> dir,回车,结果如下: 我想 ...
- 初始socket
一.客户端/服务器架构 1.C/S结构,即Client/Server(客户端/服务器)结构 2.我们在互联网中处处可见c/s架构比如说浏览器,qq,lol,视频软件... 3.我们学习socket就是 ...
- 父类和子类以及super关键字
super和this关键字的特点类似:super代表的是父类对象的引用. 当子父类的成员出现同名时,可以通过super来进行区分. 子类的构造方法中,通过super关键字调用父类的构造方法. publ ...
- 又一例网卡mtu值引发的问题
通过php上传文件到云存储,很小的文件都无法上传,在别的服务器上测试可以,本机环境是ESXI虚机安装的centos 7版本 解决思路过程 1.让开发写一个单独测试上传的文件,不调php nginx配置 ...
- 利用binlog2sql解析mysqlbinlog row行日志
binlog2sql 项目作者:曹单锋 github项目地址:https://github.com/danfengcao/binlog2sql 也可在github.com上搜索“binlog2sql” ...