JavaJUC学习篇 什么是JUC java.util 工具包、包、分类 
线程和进程 进程:一个程序,比如qq,酷我音乐啥的一个进程往往包含一个多个线程。
线程:java默认两个线程一个main,一个GC
java线程实现的方式: 
继承Thread,实现Runnable接口,实现callable
并行和并发 并行:多线程操作处理同一个资源,或者说多个人完成同一件事情
并发:为了达到某件事,每个人负责不同的模块然后完成事情。
线程的状态: 创建  —》 就绪 —》 运行 —》阻塞  —>死亡
(我们通常分为五种,但是有些情况下分为7种,加的两种为等待和超时等待)
wait和sleep的区别 首先:
wait来自Object
sleep来自Thread
其次:
wait会释放锁
sleep不会
使用范围不一样:
wait必须放到同步块中
sleep没有要求
Lock和Synchonized 传统的synchonized锁 
synchonized(){
}
括号里边一般两种
1对象
2类名.class
还有 private synchonized void name(){}
Lock接口 
ReentrantLock: 可重用锁
readLock: 读锁
writeLock:写锁
Synchronized 和 Lock 区别  
1、Synchronized 内置的Java关键字, Lock 是一个Java类 
2、Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁 
3、Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,死锁 
4、Synchronized 线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下 
去; 
5、Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以 
自己设置); 
6、Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码! 
生产者消费者问题 
生产者和消费者问题Synchronized版
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 package  com.xh.juc.day02;public  class  A  {    public  static  void  main (String[] args)  {         Date  date  =  new  Date ();         new  Thread (()->{             for  (int  i  =  0 ; i < 10 ; i++) {                 try  {                     date.increment();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"A" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 10 ; i++) {                 try  {                     date.decrement();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"B" ).start();     } } class  Date {         private  int  number  =  0 ;     public  synchronized   void  increment ()  throws  InterruptedException {         if (number != 0 ){                          this .wait();         }                  number ++ ;         System.out.println(Thread.currentThread().getName() + "=>"  +number);         this .notifyAll();     }     public  synchronized   void   decrement ()  throws  InterruptedException {         if (number == 0 ){                          this .wait();         }         number --;                  System.out.println(Thread.currentThread().getName() + "=>"  +number);         this .notifyAll();     } } 
 
生产者消费者问题:两个还好,但是到了三个或者四个就会产生问题
面试常问: 单例模式,排序算法,生产者消费者问题,死锁
问题存在:A,B,C,D四个线程的情况下出现问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public  class  B  {    public  static  void  main (String[] args)  {         Date  date  =  new  Date ();                  new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     date.increment();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"A" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     date.increment();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"B" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     date.decrement();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"C" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     date.decrement();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"D" ).start();     } } 
 
A=>1 C=>0 B=>1 A=>2 B=>3 C=>2 C=>1 C=>0 B=>1 A=>2 B=>3 C=>2 B=>3 A=>4 D=>3 D=>2 D=>1 D=>0 A=>1 D=>0
 
以上原因是由于线程产生了虚假唤醒,导致出现问题。
==解决办法,我们将if改成while判断==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class  Date1 {         private  int  number  =  0 ;     public  synchronized   void  increment ()  throws  InterruptedException {         while (number != 0 ){                          this .wait();         }                  number ++ ;         System.out.println(Thread.currentThread().getName() + "=>"  +number);         this .notifyAll();     }     public  synchronized   void   decrement ()  throws  InterruptedException {         while (number == 0 ){                          this .wait();         }         number --;                  System.out.println(Thread.currentThread().getName() + "=>"  +number);         this .notifyAll();     } } 
 
Lock解决生产者和消费者问题JUC版本的
 
基本实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 public  class  C  {    public  static  void  main (String[] args)  {         Data  data  =  new  Data ();         new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     data.increment();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"A" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     data.increment();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"B" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     data.decrement();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"C" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 5 ; i++) {                 try  {                     data.decrement();                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 }             }         },"D" ).start();     } } class   Data {    private   int  number  =  0 ;     Lock  lock  =  new  ReentrantLock ();     Condition  condition  =  lock.newCondition();               public  void  increment  ()  throws  InterruptedException {         try  {             lock.lock();             while (number != 0 ){                 condition.await();             }             number ++;             System.out.println(Thread.currentThread().getName()+"=>" + number);             condition.signalAll();         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.unlock();         }     }          public  void  decrement  ()  throws  InterruptedException {         try  {             lock.lock();             while  (number == 0 ) {                 condition.await();             }             number--;             System.out.println(Thread.currentThread().getName() +"=>" + number);             condition.signalAll();         } catch  (Exception e) {             e.printStackTrace();         } finally  {             lock.unlock();         }     } } 
 
任何一个新的技术绝对不是仅仅覆盖了一起的技术,一定会在原来的技术上进行相应的拓展
 
Condtion实现精准唤醒
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 public  class  D  {    public  static  void  main (String[] args)  {         Data2  data2  =  new  Data2 ();         new  Thread (()->{             for  (int  i  =  0 ; i < 10 ; i++) {                 data2.printA();             }         },"A" ).start();;         new  Thread (()->{             for  (int  i  =  0 ; i < 10 ; i++) {                 data2.printB();             }         },"B" ).start();         new  Thread (()->{             for  (int  i  =  0 ; i < 10 ; i++) {                 data2.printC();             }         },"C" ).start();;     } } class  Data2 {    private  int  number  =  1 ;      private  Lock  lock  =  new  ReentrantLock ();     private  Condition  condition  =  lock.newCondition();     private  Condition  condition1  =  lock.newCondition();     private  Condition  condition2  =  lock.newCondition();     public  void  printA () {         lock.lock();         try {                          while (number != 1 ){                                  condition.await();             }             System.out.println(Thread.currentThread().getName()+ "==>AA"  );             number = 2 ;             condition1.signal();         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.unlock();         }     }     public  void  printB () {         lock.lock();         try {                          while  ( number != 2 ){                 condition1.await();             }             System.out.println(Thread.currentThread().getName()+ "==>BB" );             number = 3 ;             condition2.signal();         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.unlock();         }     }     public  void  printC () {         lock.lock();         try {                          while  (number != 3 ){                 condition2.await();             }             System.out.println(Thread.currentThread().getName() + "==>CC" );             number =1 ;             condition.signal();         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.unlock();         }     } } 
 
什么是锁,如何判断锁对象(8种锁): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public  class  Test1  {    public  static  void  main (String[] args)  throws  InterruptedException {         Phone  phone  = new  Phone ();                  new  Thread (()->{             try  {                 phone.sendSms();             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }         },"A" ).start();         TimeUnit.SECONDS.sleep(1 );         new  Thread (()->{             phone.sendTel();         },"B" ).start();     } } class  Phone {    public  synchronized   void  sendSms ()  throws  InterruptedException {         TimeUnit.SECONDS.sleep(2 );         System.out.println("发短信" );     }     public  synchronized   void  sendTel () {         System.out.println("打电话" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public  class  Test2  {    public  static  void  main (String[] args)  throws  InterruptedException {                  Phone2  phone2  = new  Phone2 ();         Phone  phone  =  new  Phone ();                  new  Thread (()->{             try  {                                  phone.sendSms();             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }         },"A" ).start();         TimeUnit.SECONDS.sleep(1 );         new  Thread (()->{                         phone2.sendTel();         },"B" ).start();     } } class  Phone2 {             public  synchronized   void  sendSms ()  throws  InterruptedException {         TimeUnit.SECONDS.sleep(2 );         System.out.println("发短信" );     }     public  synchronized   void  sendTel () {         System.out.println("打电话" );     }          public  void  hello () {         System.out.println("说hello" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public  class  Test3  {    public  static  void  main (String[] args)  throws  InterruptedException {                  Phone3  phone3  = new  Phone3 ();         Phone  phone  =  new  Phone ();         new  Thread (()->{             try  {                                  phone.sendSms();             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }         },"A" ).start();         TimeUnit.SECONDS.sleep(1 );         new  Thread (()->{                          phone3.sendTel();         },"B" ).start();     } } class  Phone3 {              public  static  synchronized   void  sendSms ()  throws  InterruptedException {         TimeUnit.SECONDS.sleep(2 );         System.out.println("发短信" );     }     public  static  synchronized   void  sendTel () {         System.out.println("打电话" );     }          public  void  hello () {         System.out.println("说hello" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import  java.util.concurrent.TimeUnit;public  class  Test4  {    public  static  void  main (String[] args)  {         Phone4  phone4  =  new  Phone4 ();         Phone2  phone2  =  new  Phone2 ();         new  Thread (()->{             try  {                 phone4.sendSms();             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }         }).start();         new  Thread (()->{             phone2.sendTel();         }).start();     } } class  Phone4 {    public  static   synchronized   void  sendSms ()  throws  InterruptedException {         TimeUnit.SECONDS.sleep(2 );         System.out.println("发短信" );     }     public  synchronized   void  call () {         System.out.println("打电话" );     } } 
 
new this 具体的一个手机 
static Class 唯一的一个模板 
集合类是不安全的 
List
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public  class  ListTest  {    public  static  void  main (String[] args)  {                                                                       List<String> list = new  CopyOnWriteArrayList <>();          for  (int  i  =  1 ; i <= 10 ; i++) {             new  Thread (()->{                 list.add(UUID.randomUUID().toString().substring(0 ,5 ));                 System.out.println(list);             },String.valueOf(i)).start();         }     } } 
 
Set的不安全
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public  class  SetTest  {    public  static  void  main (String[] args)  {                                                              Set<String > set = new  CopyOnWriteArraySet <>();         for  (int  i  =  0 ; i < 10 ; i++) {             new  Thread (() -> {                 set.add(UUID.randomUUID().toString().substring(0 , 5 ));                 System.out.println(set);             }, String.valueOf(i)).start();         }     } } 
 
HashSet的底层就是HashMap
1 2 3 4 5 6 7 8 9   public  HashSet ()  {         map = new  HashMap <>();     } public  boolean  add (E e) {    return  map.put(e,PRESENT) == null ; } private  static  final  object  PRESENT  =  new  Object ();  
 
HashMap
 
回顾hashMap的 简单用法加载因子为0.75
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  class  HashMapTest  {    public  static  void  main (String[] args)  {                                                                       Map<String,String> map = new  ConcurrentHashMap <>();         for  (int  i  =  0 ; i < 10 ; i++) {             new  Thread (()->{                 map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0 ,5 ));                 System.out.println(map);             },String.valueOf(i)).start();         }     } } 
 
Callable重点讲解 
有返回值 
可以抛出异常 
方法不同,run()/call() 
 
代码测试
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public  class  CallabelTest  {                        public  static  void  main (String[] args)  throws  ExecutionException, InterruptedException {         new  Thread ().start();          MyThread1  thread  =  new  MyThread1 ();         FutureTask  futureTask  =   new  FutureTask (thread);                  new  Thread (futureTask,"A" ).start();         new  Thread (futureTask,"B" ).start();          Integer  o  =  (Integer)futureTask.get();         System.out.println(o);     } } class  MyThread  implements   Runnable {    @Override      public  void  run ()  {     } } class  MyThread1  implements  Callable <Integer>{         @Override      public  Integer call ()  throws  Exception {         System.out.println("Call()" );         return  123 ;     } } 
 
细节:
存在缓存 
结果可能需要等待,会阻塞 
 
常用的辅助类(必须掌握) CountDownLatch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public  class  CountDownLatchDemo  {    public  static  void  main (String[] args)  throws  InterruptedException {                  CountDownLatch  countDownLatch  =  new  CountDownLatch (6 );         for  (int  i  =  0 ; i < 6 ; i++) {             new  Thread ( ()->{                 System.out.println(Thread.currentThread().getName() + " \t GO OUT" );                 countDownLatch.countDown();              },String.valueOf(i)).start();         }         countDownLatch.await();                            System.out.println("关门" );     } } 
 
减法计数器:
原理是数量减一:
1 countDownLatch.countDown();  
 
 
每次有线程调用countDown()数量1,假设计数器变为0,countDownLatch.await就会被唤醒,继续执行!
CycliBarrier: 加法计数器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  class  CycliBarrierDemo  {    public  static  void  main (String[] args)  {                  CyclicBarrier  cyclicBarrier  =  new  CyclicBarrier (6 ,()->{             System.out.println("事件完成" );         });                  for  (int  i  =  1 ; i < 7 ; i++) {             final   int  temp  =  i;                          new  Thread ( ()->{                 System.out.println(Thread.currentThread().getName() + "收集" + temp + "个龙珠" );                  try  {                     cyclicBarrier.await();                   } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 } catch  (BrokenBarrierException e) {                     throw  new  RuntimeException (e);                 }             }).start();         }     } } 
 
Semaphore :  信号量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public  class  SemaphoreDemo  {    public  static  void  main (String[] args)  {                  Semaphore  semaphore  =  new  Semaphore (6 );         for  (int  i  =  0 ; i < 6 ; i++) {             new  Thread (()->{                                  try  {                     semaphore.acquire();                     System.out.println(Thread.currentThread().getName()+ "抢到车位" );                     TimeUnit.SECONDS.sleep(2 );                     System.out.println(Thread.currentThread().getName()+ "离开车位" );                 } catch  (InterruptedException e) {                     throw  new  RuntimeException (e);                 } finally  {                     semaphore.release();                 }                              },String.valueOf(i)).start();         }     } } 
 
原理: 
  semaphore.acquire();获得,假如已经满了,等待,等待被释放
   semaphore.release();释放,会将当前的信号量释放 +1 ,然后唤醒等待的线程。
读写锁 ReadWriteLock:读可以被多个线程读,但写的时候只能是一个线程写    
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 public  class  ReadWriteLockDemo  {    public  static  void  main (String[] args)  {         MyCacheLock  myCache  =  new  MyCacheLock ();         for  (int  i  =  0 ; i < 5 ; i++) {             final   int  temp  =  i;                           new  Thread (()->{                 myCache.put(temp + "" ,temp +"" );             },String.valueOf(i)).start();         }                  for  (int  i  =  0 ; i < 5 ; i++) {             final   int  temp  =  i;                           new  Thread (()->{                 myCache.get(temp + "" );             },String.valueOf(i)).start();         }     } } class  MyCache {    private   volatile  Map<String,Object> map = new  HashMap <>();          public  void  put (String key , Object obj) {         System.out.println(Thread.currentThread().getName()+ "写入" + key);         map.put(key,obj);         System.out.println(Thread.currentThread().getName()+"写入成功" );     }          public  void  get (String key) {         System.out.println(Thread.currentThread().getName()+ "读取" + key);         Object  obj  =   map.get(key);         System.out.println(Thread.currentThread().getName() + "读取成功" );     } } class  MyCacheLock {    private   volatile  Map<String,Object> map = new  HashMap <>();               private  ReadWriteLock  lock  =   new  ReentrantReadWriteLock ();          public  void  put (String key , Object obj) {                  lock.writeLock().lock();         try {             System.out.println(Thread.currentThread().getName()+ "写入" + key);             map.put(key,obj);             System.out.println(Thread.currentThread().getName()+"写入成功" );         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.writeLock().unlock();         }     }          public  void  get (String key) {                  lock.readLock().lock();         try {             System.out.println(Thread.currentThread().getName()+ "读取" + key);             Object  obj  =   map.get(key);             System.out.println(Thread.currentThread().getName() + "读取成功" );         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.readLock().unlock();         }     } } 
 
阻塞队列 队列(FIFO)
写入的时候:如果队列是满的,那么久必须阻塞等待。
取出来的时候:如果队列是空的,那么必须阻塞等待生产。
BlockingQueue
在线程下,我们使用的时候需要注意阻塞队列是多线程下并发处理,线程池处理。
学会使用队列 
添加,移除
四组API (熟练掌握并使用 )
方式 
抛出异常 
不会抛出异常 
阻塞等待 
超时等待 
 
 
添加 
add 
offer 
put 
offer(,,) 
 
移除 
remove 
poll 
take 
poll(,) 
 
判断队列首位 
element 
peek 
— 
— 
 
 
 
抛出异常 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public  class  BlockingQueueDemo  {        public  static  void  main (String[] args)  {         test1();     }          public  static  void  test1 () {                  ArrayBlockingQueue  blockingQueue  =  new  ArrayBlockingQueue <>(3 );         System.out.println(blockingQueue.add("a" ));         System.out.println(blockingQueue.add("b" ));         System.out.println(blockingQueue.add("c" ));                                           System.out.println(blockingQueue.remove());         System.out.println(blockingQueue.remove());         System.out.println(blockingQueue.remove());                  System.out.println(blockingQueue.remove());     } } 
 
不会抛出异常 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18    public  static  void  test2 () {                ArrayBlockingQueue  blockingQueue  =  new  ArrayBlockingQueue <>(3 );        System.out.println(blockingQueue.offer("a" ));        System.out.println(blockingQueue.offer("b" ));        System.out.println(blockingQueue.offer("c" ));                System.out.println(blockingQueue.offer("d" ));        System.out.println(blockingQueue.peek());         System.out.println("===========================" );        System.out.println(blockingQueue.poll());        System.out.println(blockingQueue.poll());        System.out.println(blockingQueue.poll());        System.out.println(blockingQueue.poll());      } 
 
阻塞 , 等待 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19     public  static  void  test3 ()  throws  InterruptedException {                  ArrayBlockingQueue  blockingQueue  =  new  ArrayBlockingQueue <>(3 );                  blockingQueue.put("a" );         blockingQueue.put("b" );         blockingQueue.put("c" );                System.out.println(blockingQueue.take());         System.out.println(blockingQueue.take());         System.out.println(blockingQueue.take());                      } 
 
超时等待 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16    public   static   void  test4 ()  throws  InterruptedException {        ArrayBlockingQueue  blockingQueue  =  new  ArrayBlockingQueue <>(3 );        blockingQueue.offer("a" );        blockingQueue.offer("b" );        blockingQueue.offer("c" );                blockingQueue.offer("d" ,2 , TimeUnit.SECONDS);        System.out.println(blockingQueue.poll());        System.out.println(blockingQueue.poll());        System.out.println(blockingQueue.poll());        blockingQueue.poll(2 ,TimeUnit.SECONDS);    } 
 
SynchronousQueue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public  class  SynchronousQueueDemo  {    public  static  void  main (String[] args)  {               SynchronousQueue  synchronousQueue  =   new  SynchronousQueue <>();      new  Thread (()->{          try  {              System.out.println(Thread.currentThread().getName() + "put 1"  );              synchronousQueue.put("1" );              System.out.println(Thread.currentThread().getName() + "put 2"  );              synchronousQueue.put("2" );              System.out.println(Thread.currentThread().getName() + "put 3"  );              synchronousQueue.put("3" );          } catch  (InterruptedException e) {              throw  new  RuntimeException (e);          }      },"T1" ).start();      new  Thread (()->{          try  {              TimeUnit.SECONDS.sleep(3 );              System.out.println(Thread.currentThread().getName() +"=>" + synchronousQueue.take() );              TimeUnit.SECONDS.sleep(3 );              System.out.println(Thread.currentThread().getName() +"=>" + synchronousQueue.take());              TimeUnit.SECONDS.sleep(3 );              System.out.println(Thread.currentThread().getName()+"=>" + synchronousQueue.take() );          } catch  (InterruptedException e) {              throw  new  RuntimeException (e);          }      },"T2" ).start();     } } 
 
线程池(重点) 
池化技术
 
程序的运行,本质:占用系统的资源,优化资源的使用!=>池化技术
线程池,连接池,内存池,对象池。。。  创建,销毁,十分浪费资源
池化技术,事先准备好一些资源,有人要用,就可以来我这里拿,用完之后还给我
 线程池的好处 
降低资源的消耗 
提高响应的速度 
方便管理 
 
线程复用,可以控制最大的并发数,管理线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public  class  Demo1  {    public  static  void  main (String[] args)  {              ExecutorService  threadPool  =   Executors.newCachedThreadPool();                          try  {             for  (int  i  =  0 ; i < 10 ; i++) {                 final  int  temp  =  i;                                                   threadPool.execute(()->{                     System.out.println(Thread.currentThread().getName()+ "=>"  + "OK" );                 });             }         } catch  (Exception e) {             throw  new  RuntimeException (e);         } finally  {             threadPool.shutdown();         }     } } 
 
7大参数
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43    public  static  ExecutorService newFixedThreadPool (int  nThreads)  {         return  new  ThreadPoolExecutor (nThreads, nThreads,                                       0L , TimeUnit.MILLISECONDS,                                       new  LinkedBlockingQueue <Runnable>());     }    public  static  ExecutorService newCachedThreadPool ()  {         return  new  ThreadPoolExecutor (0 , Integer.MAX_VALUE,                                        60L , TimeUnit.SECONDS,                                       new  SynchronousQueue <Runnable>());     } 	public  static  ExecutorService newSingleThreadExecutor ()  {         return  new  FinalizableDelegatedExecutorService              (new  ThreadPoolExecutor (1 , 1 ,                                     0L , TimeUnit.MILLISECONDS,                                     new  LinkedBlockingQueue <Runnable>()));     } public  ThreadPoolExecutor (     						int  corePoolSize,  //创建线程创大小                               int  maximumPoolSize, //最大核心线程的大小                               long  keepAliveTime,  //超时了,没人调用就好释放                               TimeUnit unit,	//超时单位                               BlockingQueue<Runnable> workQueue, //阻塞队列                               ThreadFactory threadFactory, //线程工厂,创建线程的,一般不用动                               RejectedExecutionHandler handler //拒绝策略)  {        if  (corePoolSize < 0  ||             maximumPoolSize <= 0  ||             maximumPoolSize < corePoolSize ||             keepAliveTime < 0 )             throw  new  IllegalArgumentException ();         if  (workQueue == null  || threadFactory == null  || handler == null )             throw  new  NullPointerException ();         this .acc = System.getSecurityManager() == null  ?                 null  :                 AccessController.getContext();         this .corePoolSize = corePoolSize;         this .maximumPoolSize = maximumPoolSize;         this .workQueue = workQueue;         this .keepAliveTime = unit.toNanos(keepAliveTime);         this .threadFactory = threadFactory;         this .handler = handler;     } 
 
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式, 这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 
说明:Executors 返回的线程池对象的弊端如下: 
1)FixedThreadPool 和 SingleThreadPool: 
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 
2)CachedThreadPool 和 ScheduledThreadPool: 
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public  class  Demo1  {    public  static  void  main (String[] args)  {                                      ExecutorService  threadPool  =  new  ThreadPoolExecutor (                 2 ,                 5 ,                 3 ,                 TimeUnit.SECONDS,                 new  LinkedBlockingQueue <>(3 ),                 Executors.defaultThreadFactory(),                 new  ThreadPoolExecutor .DiscardOldestPolicy()                 );                  try  {             for  (int  i  =  0 ; i < 10 ; i++) {                 final  int  temp  =  i;                                                   threadPool.execute(()->{                     System.out.println(Thread.currentThread().getName()+ "=>"  + "OK" );                 });             }         } catch  (Exception e) {             throw  new  RuntimeException (e);         } finally  {             threadPool.shutdown();         }     } } 
 
线程池大小如何去设置
CPU密集型和IO密集型(调优)
1 2 3 4 5 6 7 8                  System.out.println(Runtime.getRuntime().availableProcessors()); 
 
四大函数接口(必需掌握) 新时代的程序员需要掌握的lambda表达式,链式编程,函数式接口,Stream流式计算
函数式接口:只有一个方法的接口
 
比如:Runnable
简化开发模型,在新版本中大量使用
比如foreach
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public  class  FunctionDemo  {    public  static  void  main (String[] args)  {        Function  function  =  new  Function <String,String>(){                        @Override              public  String apply (String o)  {                 return  o;             }         };        Function  function1  =  (str)->{ return   str;};         System.out.println(function.apply("asd" ));         System.out.println(function1.apply("add" ));     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  class  PredicateDemo  {    public  static  void  main (String[] args)  {        Predicate  predicate  =  new  Predicate <String >(){                        @Override             public  boolean  test (String o)  {                return  o.isEmpty();            }        };                Predicate<String> predicate1 = (str)->{return  str.isEmpty();};         System.out.println(predicate.test("aad" ));         System.out.println(predicate1.test("" ));     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  class  ConsumerDemo  {    public  static  void  main (String[] args)  {         Consumer  consumer  =  new  Consumer <String>() {             @Override              public  void  accept (String o)  {                 System.out.println(o);             }         };         Consumer<String> consumer1 = (str)->{             System.out.println(str);         };         consumer.accept("你好" );         consumer1.accept("我喜欢你" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public  class  SupplierDemo  {    public  static  void  main (String[] args)  {         Supplier  supplier  =  new  Supplier <String>() {             @Override              public  String get ()  {                 return  "你好" ;             }         };         Supplier  supplier1  =  ()->{return  "我还是喜欢你" ;};         System.out.println(supplier.get());         System.out.println(supplier1.get());     } } 
 
老程序员,泛型,反射,枚举都需要会
新程序员,lambda表达式,函数式接口,Stream流式计算
什么是流式计算
 
大数据:存储+计算
集合,MySql本质上就是存储东西
计算都应该交给流来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public  class  Test  {    public  static  void  main (String[] args)  {         User  u1  =  new  User (1 ,12 ,"a" );         User  u2  =  new  User (2 ,25 ,"b" );         User  u3  =  new  User (3 ,23 ,"c" );         User  u4  =  new  User (4 ,15 ,"d" );         User  u5  =  new  User (5 ,16 ,"e" );                  List<User> list =  Arrays.asList(u1,u2,u3,u4,u5);         System.out.println(list);                  list.stream()                 .filter(u->{return   u.getId()%2  ==0 ;})                 .filter(u->{return   u.getAge() > 16 ;})                  .map(u->{return  u.getName().toUpperCase();})                  .sorted((uu1,uu2) -> {return   uu1.compareTo(uu2);})                 .limit(1 )                 .forEach(System.out::println);     } } 
 
ForkJoin ForkJoin在JDK1.7中,并行执行任务,提交效率,一般通用于大数据量!
大数据:Map Reduce(把大任务拆分为小任务)
ForkJoin特点 
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public  class  Test  {    public  static  void  main (String[] args)  throws  ExecutionException, InterruptedException {                         test3();      }               public   static   void  test1 () {         Long  start  =  System.currentTimeMillis();         Long  sum  =  0L ;         for  (long  i  =  1L ; i <= 10_0000_0000 ; i++) {             sum +=  i;         }         long  end  =  System.currentTimeMillis();         System.out.println("Sum=" +sum+"时间\t"  + (end -start));     }               public   static   void  test2 ()  throws  ExecutionException, InterruptedException {         Long  start  =  System.currentTimeMillis();         ForkJoinPool  forkJoinPool  =  new  ForkJoinPool ();         ForkJoinTask<Long> task = new  ForkJoinDemo (1L ,10_0000_0000L );         forkJoinPool.execute(task);        ForkJoinTask<Long> submit = forkJoinPool.submit(task);         Long  sum  =  submit.get();         long  end  =  System.currentTimeMillis();         System.out.println("Sum=" +"时间"  + (end -start));     }              public   static   void  test3 () {         Long  start  =  System.currentTimeMillis();         Long  sum  =  LongStream.rangeClosed(0L ,10_0000_0000L ).parallel().reduce(0 ,Long::sum);         Long  end  =  System.currentTimeMillis();         System.out.println("Sum=" +sum + "\n时间"  + (end -start));     } } 
 
异步回调 
Future设计初衷,对将来某个事件结果进行建模
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public  class  FutureDemo  {    public  static  void  main (String[] args)  throws  ExecutionException, InterruptedException {                  CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{             try  {                 TimeUnit.SECONDS.sleep(2 );             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }             System.out.println(Thread.currentThread().getName() + "RunAsny=>Void" );         });         System.out.println("111" );         completableFuture.get();         System.out.println("=================================" );                                           CompletableFuture<Integer> completableFuture1 =   CompletableFuture.supplyAsync(()->{           System.out.println(Thread.currentThread().getName() + "supplyAsync=>Integer" );            int  i  =   4 /0 ;            return  1024  ;         });       completableFuture1.whenComplete((t,u)->{           System.out.println( " --> "  +t);            System.out.println( " -- >"  + u);         }).exceptionally((e)->{           System.out.println(e.getMessage());           return  444 ;        }).get();     } } 
 
JVM初步理解 
谈谈你对Volatile的理解
 
volatile是javaJVM提供的轻量级的同步机制
保证可见性 
不保证原子性  
静止指令重排 
 
JMM:java内存模型,不存在的东西,就是一个概念!约定** 
关于JMM的一些同步的约定 
线程解锁前,必须把共享变量立刻  刷回主存。 
线程加锁前,必须读取主存中的最新值到工作内存中。 
加锁和解锁是同一把锁。 
 
线程工作内存,主内存
jvm的8种操作:
read - > load 
user -> assign 
write ->store 
lock -> unlock 
 
内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类 型的变量来说,load、store、read和write操作在某些平台上允许例外)  
lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态 
unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量 才可以被其他线程锁定 
read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便 随后的load动作使用 
load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中 
use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机 遇到一个需要使用到变量的值,就会使用到这个指令 
assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变 量副本中 
store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中, 
 
以便后续的write使用write (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内 存的变量中  
JMM对这八种指令的使用,制定了如下规则 : 
不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须 write  
不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存  
不允许一个线程将没有assign的数据从工作内存同步回主内存  
一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量 实施use、store操作之前,必须经过assign和load操作  
一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解 锁  
如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前, 必须重新load或assign操作初始化变量的值  
如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量 对一个变量进行unlock操作之前,必须把此变量同步回主内存  
 
Volatile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  class  VolatileDemo  {    private   static   int  num  =  0 ;     public  static  void  main (String[] args)  throws  InterruptedException {         new  Thread ( ()->{             while  (num == 0 ){                              }         }).start();         TimeUnit.SECONDS.sleep(1 );         num =1 ;         System.out.println(num);     } } 
 
验证特性
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  class  VolatileDemo  {         private  volatile    static   int  num  =  0 ;     public  static  void  main (String[] args)  throws  InterruptedException {         new  Thread ( ()->{             while  (num == 0 ){             }         }).start();         TimeUnit.SECONDS.sleep(1 );         num =1 ;         System.out.println(num);     } } 
 
原子性: 线程A在执行任务的时候,不能被打扰到,也不能被分割,要么同时成功要么同时失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public  class  VolatileDemo2  {         private  volatile    static   int  num  =  0 ;          public   static  void   add () {         num ++;      }     public  static  void  main (String[] args)  {                 for  (int  i  =  0 ; i < 20 ; i++) {             new  Thread (()->{                 for  (int  j  =  0 ; j < 1000 ; j++) {                     add();                 }             }).start();         }                  while  (Thread.activeCount()>2 ){             Thread.yield ();         }         System.out.println(Thread.currentThread().getName() + "  "  + num);     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public  class  VolatileDemo2  {         private  volatile    static   int  num  =  0 ;             private  static  Lock  lock  =  new  ReentrantLock ();     public   static  void   add () {         lock.lock();         try {             num ++;         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.unlock();         }     }     public  static  void  main (String[] args)  {                 for  (int  i  =  0 ; i < 20 ; i++) {             new  Thread (()->{                 for  (int  j  =  0 ; j < 1000 ; j++) {                     add();                 }             }).start();         }                  while  (Thread.activeCount()>2 ){             Thread.yield ();         }         System.out.println(Thread.currentThread().getName() + "  "  + num);     } } 
 
如果不加Lock和synochronized如何保证原子性。 
使用原子类解决原子性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public  class  VolatileDemo2  {       private  volatile   static  AtomicInteger  num  =  new  AtomicInteger ();             private  static  Lock  lock  =  new  ReentrantLock ();     public   static  void   add () {              num.getAndIncrement();      }     public  static  void  main (String[] args)  {                 for  (int  i  =  0 ; i < 20 ; i++) {             new  Thread (()->{                 for  (int  j  =  0 ; j < 1000 ; j++) {                     add();                 }             }).start();         }                  while  (Thread.activeCount()>2 ){             Thread.yield ();         }         System.out.println(Thread.currentThread().getName() + "  "  + num);     } 
 
这些类的底层都是和操作系统挂钩,在内存中修改中,Unsafe是一个特殊的存在。
指令重排
 
什么是指令重排:你写的程序,计算机并不是按照你写的程序那样去执行的。
源代码 - —  编译器里边的优化的重排 ———  指令并行也可能会重排 —  内存系统也会重排——-执行
1 2 3 4 5 int  x  =  1 ; int  y  =  2 ;x = x+ 5 ; y = x +x;   
 
可能造成影响的结果: a b x y 这四个值 默认都是 0
线程A 
线程B 
 
 
x =a 
y =b 
 
b =1 
a = 2 
 
 
 
 
 
正常的结果 x = 0; y = 0;
volatile可以避免指令重排 
内存屏障,CPU指令,作用:
保证特定的操作执行顺序 
保证某些变量的内存可见性(利用这些特性Volatile实现可见性) 
 
volatile可保证可见性,不能保证原子性,由于内存屏障,可以避免指令重排的现象产生。
内存屏障使用最多的场景是单例模式 
单例模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  class  SingleDemo  {         private   byte [] d1 =  new  byte [1024 * 1024 ];     private   byte [] d2 =  new  byte [1024 * 1024 ];     private   byte [] d3 =  new  byte [1024 * 1024 ];     private   byte [] d4 =  new  byte [1024 * 1024 ];          private   SingleDemo () {     }          private   static   SingleDemo  singleDemo  =  new  SingleDemo ();     public  static   SingleDemo getInstance () {         return   singleDemo;     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public  class  LazyDemo  {         private   LazyDemo () {         System.out.println(Thread.currentThread().getName() + "\t OK" );     }         private   volatile  static   LazyDemo lazyDemo;          public   static   LazyDemo getInstance () {                 if (lazyDemo == null ){             synchronized  (LazyDemo.class){                 lazyDemo = new  LazyDemo ();                   }                                   }         return  lazyDemo;     }               public  static  void  main (String[] args)  {         for  (int  i  =  0 ; i < 10 ; i++) {             new  Thread (()->{                 LazyDemo.getInstance();             },String.valueOf(i)).start();         }     } } 
 
1 2 3 4 5 6 7 8 9 10 11 public  class  Holder  {     private  Holder () { 	}     public  static  Holder getInstace () {          return  InnerClass.HOLDER;     }     public  static  class  InnerClass {         private  static  final  Holder  HOLDER  =  new  Holder ();     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20   public  enum  EnumSingle  {    INSTANCE;     public  EnumSingle getInstance () {         return  INSTANCE;      }  } class  Test {    public  static  void  main (String[] args)  throws  NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {          EnumSingle  instance1  =  EnumSingle.INSTANCE;          Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int .class);          declaredConstructor.setAccessible(true );         EnumSingle  instance2  =  declaredConstructor.newInstance();                  System.out.println(instance1);         System.out.println(instance2);     }  } 
 
CAS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public  class  CASDemo  {         public  static  void  main (String[] args)  {         AtomicInteger  atomicInteger  =  new  AtomicInteger (2022 );                                            System.out.println(atomicInteger.compareAndSet(2022 , 2123 ));         System.out.println(atomicInteger.get());         System.out.println(atomicInteger.compareAndSet(2020 , 2021 ));         System.out.println(atomicInteger.get());     } } 
 
CAS:比较当前工作内存中的值和主内存的值,如果这个值是期望的,那么执行操作,如果不是就一直循环
缺点: 
循环会耗时 
一次性只能保证一个共享变量的原子性 
ABA问题 
 
CAS:ABA问题(狸猫换太子)
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public  class  CASDemo  {         public  static  void  main (String[] args)  {         AtomicInteger  atomicInteger  =  new  AtomicInteger (2022 );                                                     System.out.println(atomicInteger.compareAndSet(2022 , 2123 ));         System.out.println(atomicInteger.get());         System.out.println(atomicInteger.compareAndSet(2123 , 2022 ));         System.out.println(atomicInteger.get());              System.out.println(atomicInteger.compareAndSet(2022 , 2123 ));         System.out.println(atomicInteger.get());     } } 
 
原子引用(ABA问题) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public  class  CASDemo2  {    public  static  void  main (String[] args)  {                           AtomicStampedReference<Integer> atomicStampedReference = new  AtomicStampedReference (1 ,1 );         new  Thread (()->{             int  stamp  =  atomicStampedReference.getStamp();             System.out.println( Thread.currentThread().getName()+ " "  + atomicStampedReference.getStamp());             try  {                 TimeUnit.SECONDS.sleep(2 );             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }             System.out.println(atomicStampedReference.compareAndSet(                     1 , 5 ,                     atomicStampedReference.getStamp(),                     atomicStampedReference.getStamp() + 1 ));             System.out.println( Thread.currentThread().getName()+ " -A2- "  + atomicStampedReference.getStamp());             System.out.println(atomicStampedReference.compareAndSet(                     5 , 6 ,                     atomicStampedReference.getStamp(),                     atomicStampedReference.getStamp() + 1 ));             System.out.println( Thread.currentThread().getName()+ " -A3- "  + atomicStampedReference.getStamp());         },"A" ).start();                  new  Thread (()->{             int  stamp  =  atomicStampedReference.getStamp();             System.out.println( Thread.currentThread().getName()+ " "  + atomicStampedReference.getStamp());             try  {                 TimeUnit.SECONDS.sleep(2 );             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }             System.out.println(atomicStampedReference.compareAndSet(2020 , 6666 ,                     stamp, stamp + 1 ));             System.out.println( Thread.currentThread().getName()+ " -B2- "  + atomicStampedReference.getStamp());         },"B" ).start();     } } 
 
锁机制的了解 公平锁(包含读写锁) 公平锁:非常公平,不能插队,必须先来先到
非公平锁:java自带默认非公平锁,可以插队
1 2 3 4 5    public  ReentrantLock ()  {                 sync = new  NonfairSync ();     } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public  class 公平锁 {         private  Lock  lock  =  new  ReentrantLock ();          public  static  void  main (String[] args)  {         Phone  phone  =  new  Phone ();             new  Thread (() -> {                 phone.sms();             },"A" ).start();             new   Thread (()->{                 phone.sms();             },"B" ).start();     } } class   Phone {    public   synchronized   void  sms () {         System.out.println(Thread.currentThread().getName()+"发短信" );         call();     }     public   synchronized   void   call () {         System.out.println(Thread.currentThread().getName()+"打电话" );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public  class  LockDemo  {    private  Lock  lock  =  new  ReentrantLock ();     public  static  void  main (String[] args)  {         Phone2  phone2  =  new  Phone2 ();         new  Thread (()->{             phone2.sms();         },"A" ).start();         new  Thread (()->{             phone2.sms();         },"B" ).start();         System.out.println("=====================" );         Test  te  =  new  Test ();         new  Thread (()->{             te.sms();         },"C" ).start();         new  Thread (()->{             te.sms();         },"D" ).start();     } } class  Phone2 {    private  Lock  lock  =  new  ReentrantLock ();     public   void   sms () {         lock.lock();         try {             System.out.println(Thread.currentThread().getName()+"发消息" );         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.unlock();         }         call();     }     public   void  call () {         lock.lock();         try {             System.out.println(Thread.currentThread().getName()+ "打电话" );         }catch  (Exception e){             e.printStackTrace();         }finally  {             lock.unlock();         }     } } class  Test {    public   void   sms () {         System.out.println(Thread.currentThread().getName()+"发消息" );         call();     }     public   void   call () {         System.out.println(Thread.currentThread().getName()+ "打电话" );     } } 
 
可重入锁 可重入锁是某个线程已经获得某个锁,可以再次获取锁而不会出现死锁 。再次获取锁的时候会判断当前线程是否是已经加锁的线程,如果是对锁的次数+1,释放锁的时候加了几次锁,就需要释放几次锁 。
代码中的锁的递归只是锁的一种表现及证明形式,除了这种形式外,还有另一种表现形式。同一个线程在没有释放锁的情况下多次调用一个加锁方法,如果成功,则也说明是可重入锁。
自旋锁 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public  class 自旋锁 {    AtomicReference<Thread> atomicStampedReference = new  AtomicReference <>();          public   void   myLock () {         Thread  thread  =  Thread.currentThread();         System.out.println(Thread.currentThread().getName() + "=> MY Lock" );                  while  (!atomicStampedReference.compareAndSet(null ,thread)){         }     }          public  void  myUnLock () {         Thread  thread  =  Thread.currentThread();         System.out.println(Thread.currentThread().getName() + "=> MY UnLock" );         atomicStampedReference.compareAndSet(thread,null );     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public  class  Test_Self  {    public  static  void  main (String[] args)  {                           自旋锁  t = new  自旋锁();         new  Thread (()->{             t.myLock();             try  {                 TimeUnit.SECONDS.sleep(3 );             } catch  (Exception e) {                 throw  new  RuntimeException (e);             } finally  {                 t.myUnLock();             }         },"A" ).start();         new  Thread (()->{             t.myLock();             try  {                 TimeUnit.SECONDS.sleep(1 );             } catch  (Exception e) {                 throw  new  RuntimeException (e);             } finally  {                 t.myUnLock();             }         },"B" ).start();     } } 
 
悲观锁 总是以悲观的角度来看问题,当用户拿到锁之后,认为用户会修改
乐观锁 总是以乐观的方式看待问题,当用户每次拿到锁后,都不会对数据进行修改
死锁 两个线程强制一个资源造成的两个线程处于等待状态,在不经过人的干预的情况之下一直会保持这种状态,我们称之为死锁。
如何去避免死锁(避免死锁产生的条件)
如何去判断线程产生死锁问题
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public  class 死锁{    public  static  void  main (String[] args)  {         String  lockA  =  "lockA" ;         String  lockB  =  "lockB" ;         new  Thread (new  MyTest (lockA,lockB),"A" ).start();         new  Thread (new  MyTest (lockB,lockA),"B" ).start();     } } class   MyTest  implements   Runnable {    private   String lockA;     private   String lockB;     public  MyTest (String lockA, String lockB)  {         this .lockA = lockA;         this .lockB = lockB;     }     @Override      public  void  run ()  {         synchronized  (lockA){             System.out.println(Thread.currentThread().getName() + "Lock A "   + "=> get "  + lockB);                          try  {                 TimeUnit.SECONDS.sleep(2 );             } catch  (InterruptedException e) {                 throw  new  RuntimeException (e);             }             synchronized  (lockB){                 System.out.println(Thread.currentThread().getName() + "Lock B "  + lockB + "=> get "  + lockA);                              }         }     } } 
 
使用   jps -l   定位进程号
 
使用    jstack   进程号  查看进程的信息 ,找到死锁问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 PS E:\IDEAProgram \juc -learning> jstack 2400 2022-10-09 21:13:37 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.261-b12 mixed mode): "DestroyJavaVM" #1 4 prio=5 os_ prio=0 tid=0x000001f454e10800 nid=0x31ec wait ing on condition [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "B" #1 3 prio=5 os_ prio=0 tid=0x000001f470d10800 nid=0x3690 waiting for moni tor entry [0x000000870e7ff000]    java.lang.Thread.State: BLOCKED (on object monitor)         at com.xh.juc.day07.锁.MyTest.run(死锁.java:40)         - waiting to lock <0x0000000775b9f8a0> (a java.lang.String)                 - locked <0x0000000775b9f8d8> (a java.lang.String)         at java.lang.Thread.run(Thread.java:748) "A" #1 2 prio=5 os_ prio=0 tid=0x000001f470d03000 nid=0x39e0 waiting for moni tor entry [0x000000870e6ff000]    java.lang.Thread.State: BLOCKED (on object monitor)         at com.xh.juc.day07.锁.MyTest.run(死锁.java:40)         - waiting to lock <0x0000000775b9f8d8> (a java.lang.String)                 - locked <0x0000000775b9f8a0> (a java.lang.String)         at java.lang.Thread.run(Thread.java:748) "Service Thread" #1 1 daemon prio=9 os_ prio=0 tid=0x000001f470ba4000 nid=0x3 ea0 runnable [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "C1 CompilerThread3" #1 0 daemon prio=9 os_ prio=2 tid=0x000001f470af0000 nid =0x3f94 waiting on condition [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "C2 CompilerThread2" #9  daemon prio=9 os_ prio=2 tid=0x000001f470aef000 nid= 0x3168 waiting on condition [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "C2 CompilerThread1" #8  daemon prio=9 os_ prio=2 tid=0x000001f470ade000 nid= 0xd1c waiting on condition [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #7  daemon prio=9 os_ prio=2 tid=0x000001f470add000 nid= 0x1d30 waiting on condition [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "Monitor Ctrl-Break" #6  daemon prio=5 os_ prio=0 tid=0x000001f470adb000 nid= 0x268c runnable [0x000000870dffe000]    java.lang.Thread.State: RUNNABLE         at java.net.SocketInputStream.socketRead0(Native Method)         at java.net.SocketInputStream.socketRead(SocketInputStream.java:116 )         at java.net.SocketInputStream.read(SocketInputStream.java:171)              at java.net.SocketInputStream.read(SocketInputStream.java:141)              at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)               at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)                at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)         - locked <0x0000000775c8d1c0> (a java.io.InputStreamReader)                 at java.io.InputStreamReader.read(InputStreamReader.java:184)               at java.io.BufferedReader.fill(BufferedReader.java:161)         at java.io.BufferedReader.readLine(BufferedReader.java:324)                 - locked <0x0000000775c8d1c0> (a java.io.InputStreamReader)                 at java.io.BufferedReader.readLine(BufferedReader.java:389)                 at com.intellij.rt.execution.application.AppMainV2$ 1.run(AppMainV2. java:49) "Attach Listener" #5  daemon prio=5 os_ prio=2 tid=0x000001f46edb9800 nid=0xd 64 waiting on condition [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4  daemon prio=9 os_ prio=2 tid=0x000001f46ee1e000 nid=0 x10e8 runnable [0x0000000000000000]    java.lang.Thread.State: RUNNABLE "Finalizer" #3  daemon prio=8 os_ prio=1 tid=0x000001f454eb7000 nid=0x2ee0 in  Object.wait() [0x000000870dcfe000]    java.lang.Thread.State: WAITING (on object monitor)         at java.lang.Object.wait(Native Method)         - waiting on <0x0000000775a08ee0> (a java.lang.ref.ReferenceQueue$ L ock)         at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)             - locked <0x0000000775a08ee0> (a java.lang.ref.ReferenceQueue$ Lock)         at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)             at java.lang.ref.Finalizer$ FinalizerThread.run(Finalizer.java:216)  "Reference Handler" #2  daemon prio=10 os_ prio=2 tid=0x000001f454eb0000 nid= 0x35e0 in Object.wait() [0x000000870dbff000]    java.lang.Thread.State: WAITING (on object monitor)         at java.lang.Object.wait(Native Method)         - waiting on <0x0000000775a06c00> (a java.lang.ref.Reference$ Lock)          at java.lang.Object.wait(Object.java:502)         at java.lang.ref.Reference.tryHandlePending(Reference.java:191)             - locked <0x0000000775a06c00> (a java.lang.ref.Reference$ Lock)              at java.lang.ref.Reference$ ReferenceHandler.run(Reference.java:153) "VM Thread" os_ prio=2 tid=0x000001f454ead800 nid=0x1f50 runnable "GC task thread#0  (ParallelGC)" os_ prio=0 tid=0x000001f454e26000 nid=0x3f00  runnable "GC task thread#1  (ParallelGC)" os_ prio=0 tid=0x000001f454e28800 nid=0x3eb0  runnable "GC task thread#2  (ParallelGC)" os_ prio=0 tid=0x000001f454e29800 nid=0x3e84  runnable "GC task thread#3  (ParallelGC)" os_ prio=0 tid=0x000001f454e2d000 nid=0x3fb8  runnable "GC task thread#4  (ParallelGC)" os_ prio=0 tid=0x000001f454e32000 nid=0x3ca0  runnable "GC task thread#5  (ParallelGC)" os_ prio=0 tid=0x000001f454e32800 nid=0x3df8  runnable "GC task thread#6  (ParallelGC)" os_ prio=0 tid=0x000001f454e35800 nid=0x3630  runnable "GC task thread#7  (ParallelGC)" os_ prio=0 tid=0x000001f454e36800 nid=0x8ec  runnable "VM Periodic Task Thread" os_ prio=2 tid=0x000001f470be6000 nid=0x21f4 waiti ng on condition JNI global references: 12 Found one Java-level deadlock: ============================= "B":   waiting to lock monitor 0x000001f454eb3c68 (object 0x0000000775b9f8a0, a  java.lang.String),   which is held by "A" "A":   waiting to lock monitor 0x000001f454eb65a8 (object 0x0000000775b9f8d8, a  java.lang.String),   which is held by "B" Java stack information for the threads listed above: =================================================== "B":         at com.xh.juc.day07.???.MyTest.run(死锁.java:40)         - waiting to lock <0x0000000775b9f8a0> (a java.lang.String)                 - locked <0x0000000775b9f8d8> (a java.lang.String)         at java.lang.Thread.run(Thread.java:748) "A":         at com.xh.juc.day07.锁.MyTest.run(死锁.java:40)         - waiting to lock <0x0000000775b9f8d8> (a java.lang.String)                 - locked <0x0000000775b9f8a0> (a java.lang.String)         at java.lang.Thread.run(Thread.java:748) Found 1 deadlock. 
 
如何检测死锁:
查看日志 
堆栈信息 
 
 
 
轻量锁 ① 当一个线程要进入同步块时,首先会创建一个Lock Record(锁记录)对象,该对象包含Displaced Mark Word和Owner。 ② 锁记录对象会拷贝对象头中的Mark Word,即Displaced Mark Word。 ③ 拷贝成功后,锁记录将owner指向对象头,然后尝试通过cas将对象头的Mark Word更改为指向Lock Record的指针,并且将对象Mark Word的锁标志位设置为“00”。 ④ 如果更新成功,则表示该对象处于轻量级锁定状态。如果失败,那么首先检测是否是可重入,如果可重入则进入执行。 ⑤ 如果不可重入,则膨胀为重量锁。(有的文章说会进行自旋,有的说不进行自旋只要存在竞争就膨胀为重量锁,美团说当只有一个等待线程时,该线程自旋。当超过一定次数或者超过一个自旋线程时直接膨胀为重量锁)。 ⑥ 释放锁时,使用cas对象头的Mark Word恢复,如果cas成功,则解锁成功。如果cas失败,则进入重量锁解锁流程。
重量锁 JDK1.6之前,锁没被优化,synchronized使用的是重量锁。重量锁需要操作系统帮忙,所以需要进行用户态到内核态的切换,同时还会带来线程上下文切换。 原理
Monitor对象分为3部分组成:Owner、EntryList和WaitSet ① JVM会创建一个Monitor对象,然后将锁对象的对象头中MarkWord改变成指向Monitor对象的指针。 ② 当其中一个线程抢占到锁后,Monitor的Owner会置为该线程id,只能有一个。 ③ 其余没抢到的,会被放置到EntryList中阻塞。 ④ 进入WAITING状态的线程,会被放在WaitSet中。
排他锁 排他锁(EXclusive Lock),又称X锁、独占锁、写锁。针对行锁。 当有事务对数据加写锁后,其他事务不能再对锁定的数据加任何锁,又因为InnoDB对select语句默认不加锁,所以其他事务除了不能写操作外,照样是允许读的(尽管不允许加读锁)。
📢主要为了在事务进行写操作时,不允许其他事务修改。
偏向锁 轻量锁每次重入和退出时还是会执行cas操作,并且要创建锁记录对象。如果在大多数情况下,锁总是由一个线程多次获得,不存在多线程竞争,就可以使用偏向锁优化。 原理 ① 第一次使用CAS将线程ID设置到对象的Mark Word。 ② 以后该线程进入同步块时,不需要CAS进行加锁,只会往当前线程的栈中添加一条Displaced Mark Word为空的Lock Record中,用来统计重入的次数。