美文网首页
线程通信

线程通信

作者: ClawHub的技术分享 | 来源:发表于2019-05-12 14:46 被阅读0次

线程的生命周期 image.png

Thread.yield();

作用
暂停当前正在执行的线程对象(及放弃当前拥有的cup资源),并执行其他线程。
注意
yield()做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。

Thread.sleep();

作用
主要是为了暂停当前线程,把cpu片段让出给其他线程,减缓当前线程的执行。
注意

  1. sleep是帮助其他线程获得运行机会的最好方法,但是如果当前线程获取到的有锁,sleep不会让出锁。
  2. 线程睡眠到期自动苏醒,并返回到可运行状态(就绪),不是运行状态。

wait()/notify()/notifyAll()

作用
wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行。
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
notifyAll ():唤醒正在排队等待资源的所有线程结束等待.
注意:
这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报java.lang.IllegalMonitorStateException异常。
因为这三个方法必须有锁对象调用,而任意对象都可以作为synchronized的同步锁,因此这三个方法只能在Object类中声明。
实例
还是之前多线程同步的例子,我们实现两个人交替向同一账户存款

public class Person implements Runnable {
    /**
     * The Account.
     */
    private int account = 0;
    @Override
    public  void run() {
        for (int i = 0; i < 100; i++) {
            synchronized (this){
                account +=1000;
                notify();
                System.out.println(Thread.currentThread().getName()+"第"+ i + "次存款,当前账户余额为" + account);
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这就是典型的等待-通知的模型

jion()方法

作用:
在A线程调用了线程B.join(),则只有线程A会进入BLOCK状态,当线程B执行完成后,A线程才会继续执行 。

public class MyTest {
    public static void main(String[] args) {

        final Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                System.out.println("t1");
            }
        });
        final Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                     Thread.sleep(500);
                    //引用t1线程,等待t1线程执行完
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2");
            }
        });
         final Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                     Thread.sleep(10);
//                    引用t2线程,等待t2线程执行完
                    t2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t3");
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}

本质:join()的本质也是等待-唤醒模式,看看他的实现:

public final synchronized void join(long millis)  
    throws InterruptedException {  
        long base = System.currentTimeMillis();  
        long now = 0;  
  
        if (millis < 0) {  
            throw new IllegalArgumentException("timeout value is negative");  
        }  
  
        if (millis == 0) {  
            while (isAlive()) {  
                wait(0);  
            }  
        } else {  
            while (isAlive()) {  
                long delay = millis - now;  
                if (delay <= 0) {  
                    break;  
                }  
                wait(delay);  
                now = System.currentTimeMillis() - base;  
            }  
        }  
    }  

即A线程先通过synchronized,获得B线程的锁,再while判断B线程是否存活,存活则wait阻塞,直到B线程执行结束退出,线程退出时会调用notifyAll()方法。
这里之所以用while方法,是为了在被唤醒之后再确认一下是否满足了条件。
因此A线程会等到B线程执行结束才会继续

面试

sleep() 和 wait() 有什么区别?

sleep():方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。

wait():wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程

notify()和 notifyAll()有什么区别?

如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

相关文章

  • ios 多线程的故事4

    线程间通信 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个...

  • 线程间通信

    线程间通信就是子线程和主线程之间的通信

  • 线程与线程,进程与进程之间的通信

    线程与线程之间的通信 一,为什么要线程通信? 1>多个线程...

  • Java基础知识02- 线程

    多线程通信 :什么是多线程通信 ?怎么进行通信 ? 多线程通信就是多个线程同时操作同一个全局变量,但是操作的动作不...

  • 《iOS高级开发之多线程编程之二》

    线程间的通信 在一个进程中,线程往往不是孤立存在的,多个线程之间经常进行通信,称为线程间通信。 NSThread ...

  • 线程通信的方法

    线程通信的方法 程序在使用多线程执行任务时,经常需要线程之间协同工作。此时,我们需要了解线程通信的手段。 线程通信...

  • Java线程通信

    线程通信 线程通信指的是多个线程在运行的期间,相互之间的数据交互协作。 1.通信方式 实现多个线程直接的协作,涉及...

  • 多线程之iOS线程间通信

    什么叫做线程间通信在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传...

  • 线程间的通信

    1>NSThread的线程间的通信将一个线程执行的结果, 传到另外一个线程 (不同的线程之间的通信都是线程通信)S...

  • iOS开发多线程--线程通信

    线程之间的通信 简单说明线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信。 线程间通...

网友评论

      本文标题:线程通信

      本文链接:https://www.haomeiwen.com/subject/ymhcaqtx.html