多线程之间的通讯(第三天)

2018-09-27  本文已影响0人  hzhang94

什么是线程之间的通信

多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同。

实现多线程直接的通讯

wait()、notify、notifyAll()方法

  1. wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。
  2. 这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
  3. 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
  4. 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
  5. 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

注意:一定要在线程同步中使用,并且是同一个锁的资源

wait()和notify()的使用示例

package top.nightliar.study.day04;

/**
 * 生产者,消费者(生产者生产一个,消费者消费一个,交替循环)
 * Created by Nightliar
 * 2018-09-13 15:35
 */
public class ThreadDemo01 {

    public static void main(String[] args) {
        Res res = new Res();
        new InPut(res).start();
        new OutPut(res).start();
    }

}

/**
 * 生成者,重新定义res对象的信息
 */
class InPut extends Thread{

    private boolean fl = false;

    private Res res;

    public InPut(Res res) {
        this.res = res;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (res) {
                if (res.flag){
                    try {
                        res.wait();       // res为两个共享的锁资源
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (fl){
                    res.name = "张三";
                    res.sex = "男";
                    fl = false;
                }else {
                    res.name = "小红";
                    res.sex = "女";
                    fl = true;
                }
                res.flag = true;
                res.notify();
            }
        }
    }

}

/**
 * 消费者,输出res信息
 */
class OutPut extends Thread{

    private Res res;

    public OutPut(Res res) {
        this.res = res;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (res) {
                if (!res.flag){
                    try {
                        res.wait();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(res.name + "," + res.sex);
                res.flag = false;
                res.notify();
            }
        }
    }

}

class Res {
    public boolean flag;
    public String name;
    public String sex;
}

Lock的用法

Lock 接口与 synchronized 关键字的区别

  1. Lock 接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
  2. Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
  3. Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。

Lock的写法

Lock lock  = new ReentrantLock();
lock.lock();
try{
    //可能会出现线程安全的操作
}finally{
    //一定在finally中释放锁
    //也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常
    lock.ublock();
}

Condition用法

Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。

Condition condition = lock.newCondition();
res. condition.await();  类似wait
res. Condition. Signal() 类似notify

使用Condition代替wait和notify

package top.nightliar.study.day04;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者,消费者(生产者生产一个,消费者消费一个,交替循环)
 * Created by Nightliar
 * 2018-09-13 15:35
 */
public class ThreadDemo02 {

    public static void main(String[] args) {
        Res2 res = new Res2();
        Condition condition = res.lock.newCondition();
        new InPut2(res, condition).start();
        new OutPut2(res, condition).start();
    }

}

/**
 * 生产者,重新定义res对象的信息
 */
class InPut2 extends Thread{

    private boolean fl = false;

    private Res2 res;

    private Condition condition;

    public InPut2(Res2 res, Condition condition) {
        this.res = res;
        this.condition = condition;
    }

    @Override
    public void run() {
        while (true) {
            try {
                res.lock.lock();
                if (res.flag){
                    condition.await();
                }
                if (fl){
                    res.name = "李四";
                    res.sex = "男";
                    fl = false;
                }else {
                    res.name = "小红";
                    res.sex = "女";
                    fl = true;
                }
                res.flag = true;
                condition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                res.lock.unlock();
            }

        }
    }

}

/**
 * 消费者,输出res信息
 */
class OutPut2 extends Thread{

    private Res2 res;

    private Condition condition;

    public OutPut2(Res2 res, Condition condition) {
        this.res = res;
        this.condition = condition;
    }

    @Override
    public void run() {
        while (true) {
            try {
                res.lock.lock();
                if (!res.flag){
                    condition.await();
                }
                System.out.println(res.name + "," + res.sex);
                res.flag = false;
                condition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                res.lock.unlock();
            }
        }
    }

}

class Res2 {
    public boolean flag;
    public String name;
    public String sex;
    public Lock lock = new ReentrantLock();
}

锁的类型

笔试题

  1. lock锁与synchronized同步锁的区别?
    • Java的关键字,在jvm层面上,lock是一个接口。
    • lock锁手动上锁,手动释放,灵活性高,synchronized自动上锁和解锁。
    • synchronized线程执行发生异常,jvm会让线程释放锁,lock在finally中必须释放锁,不然容易造成线程死锁。
上一篇 下一篇

猜你喜欢

热点阅读