操作线程的常用方法大体上有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()等等的方法的区别的更多相关文章

  1. 【CompletableFuture】CompletableFuture中join()和get()方法的区别

    一.相同点: join()和get()方法都是用来获取CompletableFuture异步之后的返回值 二.区别: 1.join()方法抛出的是uncheck异常(即未经检查的异常),不会强制开发者 ...

  2. 【原】iOS多线程之NSThread、NSOperationQueue、NSObject和GCD的区别

    区别: Thread: 是这几种方式里面相对轻量级的,但也是使用起来最负责的,你需要自己管理thread的生命周期,线程之间的同步.线程共享同一应用程序的部分内存空间, 它们拥有对数据相同的访问权限. ...

  3. java多线程之yield,join,wait,sleep的区别

    Java多线程之yield,join,wait,sleep的区别 Java多线程中,经常会遇到yield,join,wait和sleep方法.容易混淆他们的功能及作用.自己仔细研究了下,他们主要的区别 ...

  4. 多线程之join方法

    join方法的功能就是使异步执行的线程变成同步执行.也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方 ...

  5. Java基础-进程与线程之Thread类详解

    Java基础-进程与线程之Thread类详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程与线程的区别 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 ...

  6. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  7. Java线程之 InterruptedException 异常

    Java线程之 InterruptedException 异常   当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法. 抛 ...

  8. 第十五章、线程之queue模块的各种队列

    目录 第十五章.线程之queue模块的各种队列 一.Queue 二.LifoQueue堆栈 三.PriorityQueue优先级队列 第十五章.线程之queue模块的各种队列 一.Queue impo ...

  9. iOS多线程之8.NSOPeration的其他用法

      本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...

随机推荐

  1. 其它电脑访问mysql被拒绝

    例如,你想myuser使用mypassword从任何主机连接到mysql服务器的话. mysql> GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'%' IDE ...

  2. JS文本框输入限制

    1上面的文本框只能输入数字代码(小数点也不能输入): CODE: <input onkeyup="this.value=this.value.replace(/\D/g,'')&quo ...

  3. ElasticSearch java API-使用More like this实现基于内容的推荐

    ElasticSearch java API-使用More like this实现基于内容的推荐 基于内容的推荐通常是给定一篇文档信息,然后给用户推荐与该文档相识的文档.Lucene的api中有实现查 ...

  4. Git常用操作命令收集

      Git常用操作命令收集 1.进入本地仓库访问位置之后执行命令 1) 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/jquery.git 查看远 ...

  5. hibernate课程 初探单表映射2-3 session简介

    hibernate流程: 1 配置对象Configurateion 读取 hibernate.cfg.xml 2 会话工厂SessionFactory 读取 user.hbm.xml(创建销毁相当耗费 ...

  6. 微信小程序时间处理问题

    环境: 开发环境: 1. Mac OS 10.12.5 2. 微信Web开发者工具 v0.18.182200 测试环境: 1. iPhone 7 2. iOS 10.3.2 3. 微信 6.5.9 问 ...

  7. spring batch 读取多个文件数据导入数据库

    项目的目录结构 需要读取文件的的数据格式 applicatonContext.xml的配置 <?xml version="1.0" encoding="UTF-8& ...

  8. 独立安装Oracle Hyperion Enterprise Performance Management 验证过程

    在安装EPM的过程中,都是安装既定的操作手册进行,只是一个过程的重复,对自己安装不会留下深刻的印象.根据自己学习体会,制定安装步骤,去验证自己学习过程中的体会,加深学习印象,解决安装中遇到的问题,模仿 ...

  9. Java 中 Double 相关问题

    在项目当中,对于double类型数据的使用比较频繁.尤其是处理金钱相关的数据,在使用Double类型的数据时,涉及到精度,显示,四舍五入等等问题. 1.  显示问题,当double 数据 小于 0.0 ...

  10. .NET 前台调用后台事件和方法实现小结

    转自:https://www.cnblogs.com/kinger906/p/3431842.html 除了下文讲的方式外,还有一种方式:html里面使用ajax写好提交方式和提交参数,然后以写一行带 ...