线程之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 * ...
随机推荐
- Spring注解之@Lazy注解,源码分析和总结
一 关于延迟加载的问题,有次和大神讨论他会不会直接或间接影响其他类.spring的好处就是文档都在代码里,网上百度大多是无用功. 不如,直接看源码.所以把当时源码分析的思路丢上来一波. 二 源码分析 ...
- devExpress GridControl gridView笔记
gridView1.Appearance.EvenRow.BackColor = Color.FromArgb(, , , ); gridView1.Appearance.OddRow.BackCol ...
- Spring scope 配置
Scope 描述的是 Spring 容器如何新建Bean的实例,Spring的Scope有以下几种,通过@Scope来注解实现: 1. Singleton: 一个Spring容器中只有一个Bean的实 ...
- CF1152C Neko does Maths
思路: 假设a <= b,lcm(a + k, b + k) = (a + k) * (b + k) / gcd(a + k, b + k) = (a + k) * (b + k) / gcd( ...
- 50道CSS基础面试题(附答案)
1 介绍一下标准的CSS的盒子模型?与低版本IE的盒子模型有什么不同的? 标准盒子模型:宽度=内容的宽度(content)+ border + padding + margin低版本IE盒子模型:宽度 ...
- vue-cli建立的项目如何在手机端运行以及如何用charles来抓包
刚开始自己在config文件夹下的index.js中的dev下的host写成的是localhost,但是发现自己不能在手机端访问,并且也不可以在charles进行抓包处理,后来把localhost改成 ...
- 常用的Homebrew命令
一些常用的Homebrew命令: 更新:brew update 安装包信息检索:brew info 安装包搜索:brew search foo 安装包列表:brew list 过时信息:brew ou ...
- JAVA中的多态概念
多态性是指同一操作作用于某一类对象,可以有不同的解释,产生不同的执行结果. 多态存在的三个必要条件 需要存在继承和实现关系 同样的方法调用而执行不同操作,运行不同代码. 在运行时父类或者接口的引用变量 ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:10.项目介绍之架构(2)
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 前言 前面我们讲到<迷你微信>服务器端的主架构,现在我们来描述一下它的模块详细信息. 网络模块 从上图我 ...
- Python Visual Studio 2015
对于一直是C#开发的我来说,上Python是老早就想的事情了. 上次有个项目开始做就说要用Python,后来因为不太熟练就给推掉了.现在终于还是有机会开始下Python之旅. 因为是在Visual S ...