线程之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 * ...
随机推荐
- python学习四(处理数据)
head first python中的一个数据处理的例子 有四个U10选手的600米成绩,请取出每个选手跑的最快的3个时间.以下是四位选手的9次成绩 James 2-34,3:21,2.34,2.45 ...
- Linux系统的vim编辑器的配置文件的初步说明
vim 编辑器的基本说明 vi编辑器的功能类似于Windows下的记事本,只能编辑普通文本,而vim编辑器则相当于Windows下的notepad++等高级编辑器,提升了代码开发效率. 将vi命令默认 ...
- Maven的学习资料收集--(四)使用Maven构建Web项目-测试
2014-08-04 23:21 2人阅读 评论(0) 收藏 编辑 删除 目录(?)[+] [-] 在srcmainjava下新建一个Servlet 修改webxml 新建JSP 测试 在 ...
- Maven的学习资料收集--(三)使用Maven构建Web项目
新建Maven项目 File - New - Other 选择Maven Project 单击Next 保持默认即可单击Next 选择Archetype为 web app单击Next 输入一些必要信息 ...
- SpringBoot | 第二十三章:日志管理之整合篇
前言 在本系列<第四章:日志管理>中,由于工作中日志这块都是走默认配置,也没有深入了解过,因为部署过程中直接使用了linux中的输出重定向功能,如java -jar xx.jar > ...
- eclipse加上电脑全黑主题的设置(win10)
eclipse加上电脑全黑主题的设置(win10) 前几天在找设置win10的边框颜色时,发现的这个高对比的功能,现在已经用了好几天了,自己感觉是真的好用,所有才分享出来,相比所谓网上的豆沙绿,果然感 ...
- jquery进阶(1)
今天我们接着来学习jQuery中的内容,包括css的操作.尺寸的操作.文档的操作.动画(有待补充),事件处理操作. 一.CSS 在css中可以设置css的基本属性 - .css("color ...
- 在浏览器地址栏按回车、F5、ctrl+F5刷新页面的区别
url地址栏里敲击enter:这样的刷新,大家可以在firebug里看一下,只有少数的请求会发送出去,而且几乎没有图片的请求,这是因为请求时会先检查本地是不是缓存了请求的图片,如果有缓存而且没有过期( ...
- Browser Window
Window 对象 Window对象表示浏览器中打开的窗口. 如果文档包含框架(iframe或iframe标签),浏览器会被html文档创建一个window对象,并为每个框架创建一个额外的window ...
- <Android 基础(二)> BroadcastReceiver
介绍 BroadcastReceiver:广播接收者,很形象,广播发送,类比生活中的广播,有能力听得到的都可以介绍到这个信息,然后在大脑中反映.对应到Android中就是SendBroadcast和o ...