Java多线程之synchronized | notify | notifyAll | wait | 两个线程交替运行

synchronized关键字:

对方法或者代码块进行加锁,当它锁定一个方法或者一个代码块的时候同一时刻最多只有一个线程执行这段代码;
这样在多线程访问同一资源时可以做到线程安全

  • 同步代码块
synchronized (obj) {
    System.out.println("同步代码块");
}
  • 同步方法
public synchronized void sync() {
    System.out.println("同步方法");
}

开发中经常使用到的一个地方:创建单例对象的时候为了保证全局只有同一个对象往往需要添加锁

  • 创建一个单例对象:线程不安全
public class Single {
    private static Single single;
    public static Single getInstance() {
        if (single == null) {
            single = new Single();
        }
        return single;
    }
}
  • 创建一个单例对象:添加synchronized保证线程安全
public class Single {
    private static Single single;
    public static Single getInstance() {
        if (single == null) {
            synchronized (Single.class) {
                if (single == null) {
                    single = new Single();
                }
            }
        }
        return single;
    }
}

notify()、notifyAll()、wait()函数介绍

  • notify()
    唤醒在此对象监视器上等待的单个线程

  • notifyAll()
    唤醒在此对象监视器上等待的所有线程

  • wait()
    在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待

我们通过一个实例来理解notify()与wait()

创建两个线程,让两个线程交替打印A B

  • A线程打印A
public static class AThread implements Runnable {
    private final Object obj;
    public AThread(Object obj) {
        this.obj = obj;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                System.out.println(Thread.currentThread().getName() + ":打印A");
                try {
                    obj.notify();
                    obj.wait();
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • B线程打印B
public static class BThread implements Runnable {
    private final Object obj;
    public BThread(Object obj) {
        this.obj = obj;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                System.out.println("\t" + Thread.currentThread().getName() + ":打印B");
                try {
                    obj.notify();
                    obj.wait();
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 启动这两个线程
public static void main(String[] args) {
    //锁对象
    Object obj = new Object();
    Thread a = new Thread(new AThread(obj), "A线程");
    Thread b = new Thread(new BThread(obj), "B线程");
    a.start();
    b.start();
}
  • 输出结果
    这里写图片描述
    我们来分析下上面代码:
    A B两个线程使用同一个锁旗标obj用来同步线程
    当A B线程启动时 同一时刻 A、B线程只有一个能进入到自己的同步代码块里面
    当线程执行到obj.notify();时会唤醒此obj监视器上等待的单个线程,这里也就是我们的B线程;继续执行到obj.wait();也就是将当前线程进行阻塞,这样依次轮回就实现了两个线程交替运行。

猜你喜欢

转载自blog.csdn.net/a_zhon/article/details/80898578
今日推荐