线程间通信

1、synchronized关键字实现原理:

方法块是通过monitorentry和monitorexit去控制,而同步方法则 是依靠方法修饰符上的ACC_SYNCHRONIZED来完成的,

两个方式都是通过获取对象的监控器实现,同时这种情况是排他的,也就是说同一个时间只能有一个线程获取对象扽监控器

 

2、监控器,对象,同步队列和执行线程的关系

线程进入同步队列,线程状态变为BLOCKED。当访问Object 的前驱(获得了锁的线程)释放了锁,则该释放操作唤醒阻塞在同步队列中的线程,使其重新 尝试对监视器的获取。

2、通知和等待机制

 

简单的办法是让消费者线程不断地循环检查变量是否符合预期,如下面代码所示,在 while循环中设置不满足的条件,如果条件满足则退出while循环,从而完成消费者的工作。

while (value != desire) { Thread.sleep(1000);

   }
   doSomething();

1)难以确保及时性。在睡眠时,基本不消耗处理器资源,但是如果睡得过久,就不能及时 发现条件已经变化,也就是及时性难以保证。

2)难以降低开销。如果降低睡眠的时间,比如休眠1毫秒,这样消费者能更加迅速地发现 条件变化,但是却可能消耗更多的处理器资源,造成了无端的浪费。

以上两个问题,看似矛盾难以调和,但是Java通过内置的等待/通知机制能够很好地解决 这个矛盾并实现所需的功能。

2、使用wait()notify () notifyAll()注意的细节

1)使用wait()、notify()和notifyAll()时需要先对调用对象加锁。

2)调用wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的等待队列。

3)notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或 notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。(也就是如果别的线程不是放lock锁,那么wait后续的无法继续执行)

4、notify会将等待队列中一个线程放到同步队列,而notifyall是将所有等待的线程进入同步队列,状态有Wait变为Block。

5、wait方法返回的前提是获得调用对象的锁

public class WaitOrNotifyDemo {
    private static Object lock = new Object();
    private static volatile boolean flag = true;

    public static void main(String[] args) {
        Thread thread = new Thread(new waitDemo(), "wiatDemo");
        thread.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread thread1 = new Thread(new notifyDemo(), "notifyDemo");
        thread1.start();
    }

    static class waitDemo implements Runnable {

        @Override
        public void run() {
            synchronized (lock) {

                while (flag) {
                    System.out.println(Thread.currentThread() + "  flag"
                            + flag + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
                /*System.out.println(flag+"flag");
                while (flag) {
                    System.out.println( "flag"
                            + flag );
                }*/
            System.out.println("end  " + Thread.currentThread() + "   flag"
                    + flag + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        }
    }

    static class notifyDemo implements Runnable {

        @Override
        public void run() {
            synchronized (lock) {
                System.out.println("start  " + Thread.currentThread() + " hold lock. notify @ " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                lock.notifyAll();
                flag = false;
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //lock.notifyAll();

            }
            //再次加锁
            synchronized (lock) {

                System.out.println("end   " + Thread.currentThread() + " hold lock again. sleep @ " +
                        new SimpleDateFormat("HH:mm:ss").format(new Date()));
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在图4-3中,WaitThread首先获取了对象的锁,然后调用对象的wait()方法,从而放弃了锁 并进入了对象的等待队列WaitQueue中,进入等待状态。由于WaitThread释放了对象的锁,

NotifyThread随后获取了对象的锁,并调用对象的notify()方法,将WaitThread从WaitQueue移到 SynchronizedQueue中,此时WaitThread的状态变为阻塞状态。NotifyThread释放了锁之后, WaitThread再次获取到锁并从wait()方法返回继续执行。

join 底层调用的wait()

如果是有时间的话那么计算当前时间和如参数时间

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值