线程之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 * ...
随机推荐
- JSONP 回调给全局变量赋值失败解决
;//回调结束标志位var 临时全局变量;var 需要接收的全局变量: function getDate(){ flag = 0; //回调 inviteService.getActivityDeta ...
- SQL Server收缩数据库
USE[master]GOALTER DATABASE CCPG_SFY SET RECOVERY SIMPLE WITH NO_WAITGOALTER DATABASE CCPG_SFY SET R ...
- Get和Post的请求
get post请求 <form method="post","get", action="a.ashx"> <input ...
- Pod管理的iOS项目修改工程名
声明:本文大部分内容来自于以下网址,其余的部分是自己尝试的总结和补充. http://www.jianshu.com/p/5f088acecf64 完整修改iOS工程名1 http://www.cnb ...
- 初识quartz 并分析 项目中spring整合quartz的配置【原创+转载】
初识quartz 并分析 项目中spring整合quartz的配置[原创+转载]2018年01月29日 12:08:07 守望dfdfdf 阅读数:114 标签: quartz 更多个人分类: 工具 ...
- 【踩坑】socket.io服务器不能访问
今天在单机测试socket.io服务器时一切正常,但用jar包的方式部署在服务器时发现客户端无法连接. 于是做了一系列排查,如检查端口是否在占用,防火墙有没有开放该端口,阿里云终端是否有开放安全组,本 ...
- wcf post
服务端: 1.接口 [OperationContract] [ServiceKnownType(typeof(CreatMicroBlogFeedViewModel))] [WebInvoke(Bod ...
- spring mvc 文件下载 get请求解决中文乱码问题
方案简写,自己或有些基础的可以看懂,因为没时间写的那么详细 方案1 spring mvc解决get请求中文乱码问题, 在tamcat中server.xml文件 URIEncoding="UT ...
- Browser Window
Window 对象 Window对象表示浏览器中打开的窗口. 如果文档包含框架(iframe或iframe标签),浏览器会被html文档创建一个window对象,并为每个框架创建一个额外的window ...
- html便民查询各个工具类实例代码分享(支持pc和移动端)
1.手机号码查询 <iframe id="api_iframe_51240" name="api_iframe_51240" src="&quo ...