线程之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;
    }
}

原文地址:https://www.cnblogs.com/huangwentian/p/9165155.html

时间: 2024-11-05 16:00:39

线程之sleep(),wait(),yield(),join()等等的方法的区别的相关文章

java多线程之sleep()与yield()的区别

1.使用sleep()暂停当前线程之后,其他的线程会获得执行机会,但是调用yield()之后,只有优先级和当前线程优先级相同或者更高的线程才能获取执行的机会. 2.使用sleep()会使线程进入阻塞状态,之后在阻塞时间过去之后,线程才能继续执行,但是使用yield()只是强制当前线程进入就绪状态,有可能调用yield()之后,当前线程立即又获得执行机会. 3.使用sleep()需要捕捉异常,但是使用yield()则不需要捕捉. 4.sleep()比yield()具有更好的可移植性,通常不建议使用

iOS多线程之NSThread、NSOperationQueue、NSObject和GCD的区别

区别: Thread: 是这几种方式里面相对轻量级的,但也是使用起来最负责的,你需要自己管理thread的生命周期,线程之间的同步.线程共享同一应用程序的部分内存空间, 它们拥有对数据相同的访问权限.你得协调多个线程对同一数据的访问,一般做法是在访问之前加锁,这会导致一定的性能开销.在 iOS 中我们可以使用多种形式的 thread. Cocoa threads(NSObject): 使用 NSThread 或直接从 NSObject 的类方法 performSelectorInBackgrou

多线程之join方法

join方法的功能就是使异步执行的线程变成同步执行.也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法.如果不使用join方法,就不能保证当执行到start方法后面的某条语句时,这个线程一定会执行完.而使用join方法后,直到这个线程退出,程序才会往下执行.下面的代码演示了join的用法. package mythread; public class JoinThread extends Thre

Java多线程之join

将另外一个线程join到当前线程,则需要等到join进来的线程执行完才会继续执行当前线程. package Thread.join; class Sleeper extends Thread { private int duration; public Sleeper(String name, int sleepTime) { super(name); duration = sleepTime; start(); } public void run() { try { sleep(duratio

多线程之Join

Join方法,其实简单的说就是阻止主线程运行,知道子线程完成后才继续执行主线程.注意这里只是阻止主线程. 下面是个例子: myThread.Join() Console.WriteLine("Child joined"); 运行结果是:先显示myThread线程内的内容,然后显示Child joined. 从这里可以看到,当调用Join方法后,Console语句需要等待myThread这个子线程执行完后才能输出(因为Console属于主线程). 多线程之Join

JAVA多线程之wait/notify

本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait() 与  notify/notifyAll() 的执行过程 ③中断 调用wait()方法进入等待队列的 线程 ④notify 通知的顺序不能错 ⑤多线程中测试某个条件的变化用 if 还是用 while? ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 wait()

java多线程之ThreadLocal

ThreadLocal保证数据同步 package Thread.Common; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class Accessor implements Runnable { private final int id; pub

OC多线程之GCD ----- 2

dispatch_create生成的Queue不管是并行队列还是串行队列,其优先级都是默认优先级 但是可以用dispatch_set_target_queue来改变队列的优先级 dispatch_set_target_queue(原来的队列, 目标优先级队列) 使用这个函数需要获取两个队列,一个是需要变更优先级的队列,一个是指定优先级的队列(指定优先级的队列可以通过get_global获得) 如果多个串行队列优先级相同,那么这些队列里的任务也会串行执行 dispatch_after函数并不能非常

多线程之AutoResetEvent

我们在线程编程的时候往往会涉及到线程的通信,通过信号的接受来进行线程是否阻塞的操作. AutoResetEvent 允许线程通过发信号互相通信.通常,此通信涉及线程需要独占访问的资源. AutoResetEvent 的方法有很多,具体方法和扩展方法请详见AutoResetEvent类,最常用方法中就有Set()和WaitOne(). 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号.如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的