java线程间通信

java线程间通信

java线程间通信模型可分为两种:共享内存和消息传递。该文章主要对共享内存的方式介绍线程间的通信

一、volatile 关键字

使用volatile关键字修饰变量,将会使变量线程间可见即每次获取都是最新的值。如下文的示例代码,通过volatile修饰标志变量flag,使得线程在获取flag的值时总是最新的,每个线程对flag进行更改,以此达到线程间的通信

public class VolatileDemo {
    volatile Boolean flag = false;


    public static void main(String[] args) {
        VolatileDemo volatileDemo = new VolatileDemo();

        // 生产者任务
        Thread producerThread = new Thread(volatileDemo.producer());
        producerThread.start();

        // 消费者
        Thread consumerThread = new Thread(volatileDemo.consumer());
        consumerThread.start();

    }

    public Runnable producer() {
        return new Runnable() {
            @Override
            public void run() {
                while (true) {
                    // 当flag为false时,生产
                    while (!flag) {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        flag = true;
                        System.out.println("Produce complete: " + System.currentTimeMillis());
                    }
                }
            }
        };
    }

    public Runnable consumer() {
        return new Runnable() {
            @Override
            public void run() {
                while (true) {
                    // 当flag为true时,消费
                    while (flag) {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        flag = false;
                        System.out.println("Consume complete: " + System.currentTimeMillis());
                    }
                }
            }
        };
    }

}

// 执行结果
Produce complete: 1597651318001
Consume complete: 1597651320001
Produce complete: 1597651322002
Consume complete: 1597651324002
Produce complete: 1597651326002
Consume complete: 1597651328003
...
    
// 当去掉volatile关键字后的执行结果
Produce complete: 1597651376746

上述代码的执行结果中,当volatile关键字去掉后,由于生产者线程修改的flag并没有即时写入主内存,导致消费者线程读取的变量值总是为false。

二、synchronized关键字+wait()、notify()

通过synchronized关键字修饰方法、代码块时实现线程同步时需要获取到锁,其锁对象也需要是同一个,因此实际上也是共享内存变量的模型。

public class SynchronizedDemo {
    static final Object lockObj = new Object();

    public static void main(String[] args) throws InterruptedException {
        // 生产者
        Thread producer = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lockObj){
                    while (true){
                        try {
                            Thread.sleep(2000);
                            System.out.println("Produce complete : "+ System.currentTimeMillis());
                            lockObj.notifyAll();
                            lockObj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        producer.start();
        
        // 消费者
        Thread consumer = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lockObj){
                    while (true){
                        try {
                            Thread.sleep(2000);
                            System.out.println("Consume complete : "+ System.currentTimeMillis());
                            lockObj.notifyAll();
                            lockObj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        consumer.start();
    }
}

//执行结果
Produce complete : 1597653867586
Consume complete : 1597653869587
Produce complete : 1597653871587
Consume complete : 1597653873587
Produce complete : 1597653875588
Consume complete : 1597653877589
...

上面的代码中,通过共享lockObj这个对象的,两个进程各自通过lockObj的wati()释放锁并等待,通过notifyAll()方法相互唤醒,实现了两个线程间的通信。

三、ReentrantLock+Condition

该方法与synchronized类似,也是共享一个对象,不过这里共享的是ReentrantLock锁对象。ReentrantLock对象的newCondition()方法可以返回其Condition对象,该Condition对象有独有的await()和signal()、signalAll()方法,类似于Object对象的wait()和notify()方法,但是拥有更灵活的扩展用法。

public class ReentrantLockDemo {
    final static ReentrantLock lock = new ReentrantLock();
    final static Condition condition = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        // 生产者
        Thread producer = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        lock.lock();
                        Thread.sleep(2000);
                        System.out.println("Produce complete : " + System.currentTimeMillis());
                        condition.signalAll();
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        });
        producer.start();

        Thread.sleep(500);
        // 消费者
        Thread consumer = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        lock.lock();
                        Thread.sleep(2000);
                        System.out.println("Consume complete : " + System.currentTimeMillis());
                        condition.signalAll();
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        });
        consumer.start();
    }
}

// 执行结果
Produce complete : 1597654555715
Consume complete : 1597654557715
Produce complete : 1597654559716
Consume complete : 1597654561716
...

四、CyclicBarrier

CyclicBarrier可以理解为一个栅栏,等所有的线程都执行到指定的进度——栅栏之后,每个线程才会继续运行栅栏之后的任务。

public class CyclicBarrierDemo {
    final static CyclicBarrier barrier = new CyclicBarrier(3);

    public static void main(String[] args) {
        // 线程1
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread()+"Stopped at barrier");
                    barrier.await();
                    System.out.println(Thread.currentThread()+"More task");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // 线程2
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread()+"Stopped at barrier");
                try {
                    barrier.await();
                    System.out.println(Thread.currentThread()+"More task");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // 线程3
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread()+"Stopped at barrier");
                try {
                    barrier.await();
                    System.out.println(Thread.currentThread()+"More task");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

// 执行结果
Thread[Thread-1,5,main]Stopped at barrier
Thread[Thread-2,5,main]Stopped at barrier
Thread[Thread-0,5,main]Stopped at barrier
Thread[Thread-0,5,main]More task
Thread[Thread-1,5,main]More task
Thread[Thread-2,5,main]More task

在线程1中,sleep了1秒,使得线程2和3先到达栅栏,等线程1也到达栅栏后,每个线程后续的任务才继续执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值