Object调用的wait和notify Condition调用的await和single对线程加锁及等待唤醒顺序都有要求,违反规则将发生线程异常情况;LockSupport调用的park和unpark对线程没有加锁需求,且可以先发生唤起再执行等待(先unpark再park),底层用的permit(0,1) least 0,most 1;严格要求唤起与等待成对出现
# Object和Condition对等待唤醒的约束:Ⅰ线程要先获取并持有锁,即代码必须在同步代码块中    Ⅱ必须先等待后唤醒,不然阻塞
 ## wait和notify(Object方法)
 wait  synchronized  notify
 ```java
 /**
  * wait和notify方法必须再同步代码块中执行,且需要成对有序出现(先wait再notify)
  */
 public class Test {
 static Object objectLock = new Object();
 public static void main(String[] args)
     {
         new Thread(() -> {
             //暂停几秒钟线程
             try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
             synchronized (objectLock){
                 System.out.println(Thread.currentThread().getName()+"\t"+"---come in");
                 try {
                     objectLock.wait();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 System.out.println(Thread.currentThread().getName()+"\t"+"---被唤醒");
             }
         },"t1").start();
        //暂停几秒钟线程
         try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        new Thread(() -> {
             synchronized (objectLock){
                 objectLock.notify();
                 System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
             }
         },"t2").start();
     }
 }
 ```
 - 如果没有在同步代码(sync锁)块中执行
 
- 如果先运行notify再运行wait将会发生阻塞
 
 ## await和signal(Condition方法) 
 await  lock/lock  signal
 ``` java
  /**
      *
      *Condtion中线程等待和唤醒方法之前需要获取锁   await和signal要有先后,不然发生阻塞
      */
 public class Test2 {
     static Lock lock = new ReentrantLock();
     static Condition condition = lock.newCondition();
     public static void main(String []args)
     {
         new Thread(() -> {
             //暂停几秒钟线程
             try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
             lock.lock();
             try
             {
                 System.out.println(Thread.currentThread().getName()+"\t"+"---come in");
                 condition.await();
                 System.out.println(Thread.currentThread().getName()+"\t"+"---被唤醒");
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } finally {
                 lock.unlock();
             }
         },"t1").start();
        new Thread(() -> {
             lock.lock();
             try
             {
                 condition.signal();
                 System.out.println(Thread.currentThread().getName()+"\t"+"---发出通知");
             }finally {
                 lock.unlock();
             }
         },"t2").start();
     }
 }
 ```
 - await前没加 lock.lock()
 
- 如果先执行signal将发生阻塞
 
 ## park与unpark(LockSupport)
 ```java
 /**
      * 无锁块要求  先唤醒还是先等待不影响执行结果   park与unpark要成双成对
      * 通信证只用一次 permit (0, 1)   默认是0 累加上限是1
      */
     public static void main(String[] args) {
         Thread t1 = new Thread(() -> {
             System.out.println(Thread.currentThread().getName() + "\t" + "---come in");
             LockSupport.park();
             LockSupport.park();
             System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒");
         }, "t1");
         t1.start();
        new Thread(() -> {
             LockSupport.unpark(t1);
            try {
                 TimeUnit.SECONDS.sleep(3);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             LockSupport.unpark(t1);
             System.out.println(Thread.currentThread().getName() + "\t" + "---发出通知");
         }, "t2").start();
     }
 ```
 正确使用LockSupport提供的通行证可最大程度避免线程阻塞  每个线程只能使用一个通行证,permit值域(0,1),因此park与unpark要成对出现











