线程之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 * ...
随机推荐
- Sqoop架构
Sqoop 架构 Sqoop 架构是非常简单的,它主要由三个部分组成:Sqoop client.HDFS/HBase/Hive.Database.下面我们来看一下 Sqoop 的架构图. 用户向 Sq ...
- 熟悉servlet的页面跳转
jspweb里面用到的servlet跳转页面的方法 使用的jar包只有 commons-lang3-3.5.jar 运行时,tomcat会先根据web.xml里面的信息,查找servlet <? ...
- Java学习笔记--关于面向对象的思考
1.不可改变的类生成对象以及变量的范围 2. 关键词this的使用 3.用类抽象的思想制作软件 4.通过关系模型建立类 5.使用面向对象的范例来设计程序,遵循类设计指导. 已经学习了:怎么定义类已经创 ...
- jQuery图片组展示插件----Galleria使用简介
1.技术目标 掌握Galleria插件的基本操作 2.Galleria简介 Galleria是一个jQuery插件,可用于展示多张图片,操作也比较简单, 展示效果也非常不错,如图: 提示:Galler ...
- 解决WinSCP连接虚拟机
其实虚拟机你也可以将它形象化,认为它就是一台电脑,只是这个电脑在你的内存中,所以,一般电脑所具有的的功能虚拟机一样拥有,它也可以当成一台独立的个体哦. 针对很多使用WinSCP连接不上虚拟机的问题,这 ...
- Django组件:forms组件(简易版)
一.校验字段功能 1.模型:models.py class UserInfo(models.Model): name=models.CharField(max_length=32) pwd=model ...
- python随笔---录入月份的值,输出对应的季节
首先获取一个输入,加判断,输入对应的月份,季节判定根据气象划分法(气象划分法:在气象部门,通常以阳历3-5月为春季,6-8月为夏季,9-11月为秋季,12月-来年2月为冬季,并且常常把1.4.7.10 ...
- The eighth day
time n(名词):时间:次,时代,时刻: vt(及物动词):为...安排时间:测定...的时间:调准(机械的速度): vi(不及物动词):合拍,和谐,打拍子 files (原型是fly) vi(不 ...
- js绑定事件方法:addEventListener的兼容问题
js的事件绑定方法中,ie只支持attachEvent,而FF和Chrome只支持addEventListener;严格来说:addEventListener只有IE9以上版本的IE浏览器上能够兼容, ...
- SqlServer作业指定目标服务器
用SSMS生成数据库作业的创建脚本的时候,有一步是sp_add_jobserver操作: EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = ...