JUC使用整理笔记

常用工具类

 1.org.apache.common.io.IOUtils
 1.org.apache.common.io.FileUtils
 1.org.apache.common.lang.StringUtils
 1.org.apache.common.lang.ArrayUtils
 1.org.apache.common.lang.StringEscapeUtils
 1.org.apache.http.util.EntityUtils
 1.org.apache.common.lang3.StringUtils

 

 

 

 

 PDF获取地址:

链接:https://pan.baidu.com/s/17hGKm4efC8di7azQy9yenA
提取码:4vwx

1.Thread分析

Java无法开启线程,开启线程使用的是native方法,调用C++

 new Thread().start();
 //========================
 group.add(this);
 start0();
 private native void start0();

  

线程的状态

 public enum State {
  //新建、运行、阻塞,等待,超时等待,终止
     NEW, RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
 }

  

wait/sleep区别

1.所属类不同 wait 是object的方法,sleep是thread的方法

sleep调用:TimeUnit.SECONDS.sleep(1);//为JUC的类

2.是否释放锁:wait 会释放锁,sleep抱着锁不会释放

3.使用范围不同 wait 需要在同步代码块中 sleep在任何地方都可以

4.wait 不需要捕获异常,sleep需要

2.Lock

1.接口

实现类:ReentrantLock ReadWriteLock

2.sychronized与lock区别

1.sychronized是Java的内置关键字,lock是类

2.sychronized无法获取锁状态,lock可以显示指定锁状态

3.sychronized会自动释放锁,lock需要手动释放【死锁】

4.sychronized会等待,lock可以通过trylock不用等待

5.sychronized是可重入锁,不可以中断,非公平,lock可重入锁,可以判断锁(tryLock),非公平【默认】

6.sychronized适合少量代码,lock适合大量代码

生产者消费者模型

 //生产者消费者模型
 //书写步骤
 //判断是否等待 执行业务  通知
 //多线程执行任务类的内容: 属性 方法
 class Data{
     private int num = 0;
     public synchronized void increment() throws InterruptedException {
         //判断是否等待
         if(num != 0){
             this.wait();
         }
         //执行业务
         num++;
         System.out.println(Thread.currentThread().getName()+ " --->" + num);
         //进行通知
         this.notifyAll();
     }
 ​
 ​
     public synchronized void decrement() throws InterruptedException {
         //判断是否等待
         //======================
         //这块使用if 多个线程情况下容易出现虚假唤醒问题-----
         if(num == 0){
             this.wait();
         }
         //指定业务
         num--;
         System.out.println(Thread.currentThread().getName()+ " --->" + num);
         //通知
         this.notifyAll();
     }
 }
 ​
 public static void main(String[] args) {
     Data data = new Data();
     new Thread(()->{
         for (int i = 0; i <10 ; i++) {
             try {
                 data.increment();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     },"A").start();
     new Thread(()->{
         for (int i = 0; i <10 ; i++) {
             try {
                 data.decrement();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     },"B").start();
 ​
 }
 B --->0
 A --->1
 B --->0
 A --->1
 B --->0
 A --->1
 B --->0
 A --->1
 B --->0
 A --->1
 B --->0
 A --->1
 B --->0
 A --->1
 B --->0
 A --->1
 B --->0

  

2.1虚假唤醒问题

上面代码在多个线程情况下会出现问题,如当为4个线程时,数据就不正确了,是由于虚假唤醒造成的

怎样解决?

可以使用while进行判断

 //使用while来进行虚假唤醒等待判断
 while (num !=0){
     this.wait();
 }

  

2.2sychronized与lock区别

在多线程中,多个线程访问synchronized代码块,线程之间需要通信,此时可以使用wait和notify进行线程间的通信。

而在Lock中,也存在同样的通信操作,Condition取代了对象监视器的使用,使用Condition进行线程间的通信操作,condition.await();//等待操作。condition.signal()通知操作

2.2.1 使用Lock结合condition进行判断

 public class PC {
 ​
     //生产者消费者模型
     public static void main(String[] args) {
         Data data = new Data();
         new Thread(()->{
             for (int i = 0; i <10 ; i++) {
                 try {
                     data.increment();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         },"A").start();
         new Thread(()->{
             for (int i = 0; i <10 ; i++) {
                 try {
                     data.decrement();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         },"B").start();
 ​
         new Thread(()->{
             for (int i = 0; i <10 ; i++) {
                 try {
                     data.increment();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         },"C").start();
 ​
         new Thread(()->{
             for (int i = 0; i <10 ; i++) {
                 try {
                     data.decrement();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         },"D").start();
 ​
     }
 }
 ​
 ​
 class Data{
     private int num = 0;
     //使用lock实现
     Lock lock = new ReentrantLock();
     Condition condition = lock.newCondition();
 ​
     public  void increment() throws InterruptedException {
      try{
          lock.lock();
          //================执行业务代码
          //判断是否等待
          while (num !=0){
              condition.await();
          }
          //执行业务
          num++;
          System.out.println(Thread.currentThread().getName()+ " --->" + num);
          //进行通知
          condition.signalAll();
      }catch (Exception e){
 ​
      }finally {
          lock.unlock();
      }
     }
 ​
 ​
     public  void decrement() throws InterruptedException {
         lock.lock();
      try{
          //判断是否等待
          while (num ==0){
              condition.await();
          }
          //指定业务
          num--;
          System.out.println(Thread.currentThread().getName()+ " --->" + num);
          //通知
          condition.signalAll();
      }catch(Exception e){
      
      }finally{
      lock.unlock();
      }
     }
 }
使用这种方式结果是随机的

  

2.2.2 condition可以精准的通知和唤醒线程

构造多个condition进行符合条件的唤醒

 public class PC {
 ​
     //生产者消费者模型
     public static void main(String[] args) {
         Data data = new Data();
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.increment();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "A").start();
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.increment1();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "B").start();
 ​
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.decrement();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "C").start();
 ​
         new Thread(() -> {
             for (int i = 0; i < 10; i++) {
                 try {
                     data.decrement1();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }, "D").start();
 ​
     }
 }
 ​
 ​
 class Data {
     private int num = 1;
     //使用lock实现
     Lock lock = new ReentrantLock();
     Condition conditionA = lock.newCondition();
     Condition conditionB = lock.newCondition();
     Condition conditionC = lock.newCondition();
     Condition conditionD = lock.newCondition();
 ​
     public void increment() throws InterruptedException {
         try {
             lock.lock();
             //================执行业务代码
             //判断是否等待
             while (num != 1) {
                 conditionA.await();
             }
             //执行业务
             System.out.println(Thread.currentThread().getName() + " --->" + num);
             num = 2;
             //进行通知
             conditionB.signal();
         } catch (Exception e) {
 ​
         } finally {
             lock.unlock();
         }
     }
 ​
     public void increment1() throws InterruptedException {
         try {
             lock.lock();
             //================执行业务代码
             //判断是否等待
             while (num != 2) {
                 conditionB.await();
             }
             //执行业务
             System.out.println(Thread.currentThread().getName() + " --->" + num);
             num=3;
             //进行通知
             conditionC.signal();
         } catch (Exception e) {
 ​
         } finally {
             lock.unlock();
         }
     }
 ​
     public void decrement() throws InterruptedException {
         lock.lock();
         try {
             //判断是否等待
             while (num != 3) {
                 conditionC.await();
             }
             //指定业务
             System.out.println(Thread.currentThread().getName() + " --->" + num);
             num = 4;
             //通知
             conditionD.signal();
         } catch (Exception e) {
 ​
         } finally {
             lock.unlock();
         }
     }
 ​
     public void decrement1() throws InterruptedException {
         lock.lock();
         try {
             //判断是否等待
             while (num != 4) {
                 conditionD.await();
             }
             //指定业务
             System.out.println(Thread.currentThread().getName() + " --->" + num);
             num = 1;
             //通知
             conditionA.signal();
         } catch (Exception e) {
 ​
         } finally {
             lock.unlock();
         }
     }
 }

  

2.3锁的8个问题

1.synchronized 锁的对象是方法的调用者

集合不安全

List不安全-CopyOnWriteArrayList

List<String> list = new ArrayList<>();
for (int i = 0; i <= 10; i++) {
    new Thread(
            () -> {
                /**
                 * 并发下的ArrayList是不安全的
                 * 会报:java.util.ConcurrentModificationException
                 */
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            }, String.valueOf(i)
    ).start();
}

  //解决方法
  //1.使用Vector,底层是使用synchronized
  List<String> vector = new Vector<>();
  for (int i = 0; i <= 10; i++) {
      new Thread(
              () -> {
                  vector.add(UUID.randomUUID().toString().substring(0, 5));
                  System.out.println(vector);
              }, String.valueOf(i)
      ).start();
  }



  //2.使用List的顶级接口Collections.synchronizedList
  /**
   * public void add(int index, E element) {
   *             synchronized (mutex) {list.add(index, element);}
   *         }
   */
 List<String> vector = Collections.synchronizedList(new ArrayList<>());
 for (int i = 0; i <= 10; i++) {
     new Thread(
             () -> {
                 vector.add(UUID.randomUUID().toString().substring(0, 5));
                 System.out.println(vector);
             }, String.valueOf(i)
     ).start();
 }

  /**
   * CoryOnWrite COW :写入时复制,计算机领域的一种优化策略
   * 多线程读时,其是固定的
   * 多线程写时,其是使用复制,从而避免覆盖,造成数据并发修改问题
   */
  //3.使用CoryOnWriteArrayList
  /**
   *  private transient volatile Object[] array;
   *  final ReentrantLock lock = this.lock;
   */
  List<String> vector = new CopyOnWriteArrayList<>();
  for (int i = 0; i <= 10; i++) {
      new Thread(
              () -> {
                  vector.add(UUID.randomUUID().toString().substring(0, 5));
                  System.out.println(vector);
              }, String.valueOf(i)
      ).start();
  }

  

Set不安全-CopyOnWriteArraySet

public static void main(String[] args) {
    //Set<String> set = new HashSet<>();
    //Set<String> set = Collections.synchronizedSet(new HashSet<>());
    Set<String> set  = new CopyOnWriteArraySet<>();
    for (int i = 0; i <= 10; i++) {
        new Thread(
                () -> {
                    /**
                     * 并发下的HashSet是不安全的
                     * 会报:java.util.ConcurrentModificationException
                     */
                    set.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(set);
                }, String.valueOf(i)
        ).start();
    }

}

  

Map不安全-ConcurrentHashMap

/**
     * 1.一般不使用HashMap
     * 2.默认HashMap<>(16,0.75)
     */
    //Map<String,String> map = new HashMap<>();
    Map<String,String> map  = new ConcurrentHashMap<>();
    for (int i = 0; i <= 10; i++) {
        new Thread(
                () -> {
                    /**
                     * 并发下的HashMap是不安全的
                     * 会报:java.util.ConcurrentModificationException
                     */
                    map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(map);
                }, String.valueOf(i)
        ).start();
    }

}

  

Callable

1.有返回值 2.会抛出检查异常 3.call()调用

Callable中call方法的调用时,需要使用FutureTask通过中间方式进行调用

new Thread(new Runnable()).start();

new Thread(new FutureTask(new Callable(){})).start(); //FutureTask是Runnable的实现类

1.task.get(): 会阻塞 2.多线程调用多次,任务只会执行一次:有缓存

public class CallableTest {
    /**
     * 1.task.get(): 会阻塞
     * 2.多线程调用多次,任务只会执行一次:有缓存
     */
    public static void main(String[] args) throws Exception {
       //new Thread(new Runnable()).start();
       //new Thread(new FutureTask<String>(new CallTest()),"A").start();
        CallTest test = new CallTest();
        //FutureTask构造方法中有两种方法 1.Callable 2. Runnable
        FutureTask<String> task = new FutureTask<String>(test);
        new Thread(task,"A").start();
        //call方法只会调用一次
        new Thread(task,"B").start();
        //get是阻塞操作,异步处理
        String str = task.get();
        System.out.println(str);
    }

}

class CallTest implements Callable<String>{
    @Override
    public String call() throws Exception {
        System.out.println("---------");
        return "13";
    }
}

  

常用的辅助类

1.CountDownLatch

允许一个线程或多个线程进行等待,直到其他线程操作完成,它是一个辅助类

如业务:下订单-扣减库存-使用优惠劵-付款-增加积分:使用CountDownLatch初始5个线程,5个线程执行完成后再执行其他方法

/**
     * 下订单-扣减库存-使用优惠劵-付款-增加积分->   通知发货
     * @param args
     * @throws InterruptedException
     */

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch cdl = new CountDownLatch(5);
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "--   下订单");
            //执行一个减一
            cdl.countDown();
        },"下订单").start();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "--   扣减库存");
            //执行一个减一
            cdl.countDown();
        },"扣减库存").start();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "--   使用优惠劵");
            //执行一个减一
            cdl.countDown();
        },"使用优惠劵").start();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "--   付款");
            //执行一个减一
            cdl.countDown();
        },"付款").start();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "--   增加积分");
            //执行一个减一
            cdl.countDown();
        },"增加积分").start();
        //计速器未归零时阻塞
        cdl.await();
        //计数器归零后向下执行
        System.out.println("================");
        System.out.println("执行 通知发货");

    }

  

2.CyclicBarrier

允许一组线程全部等待彼此达到共同屏障点的同步辅助类

new CyclicBarrier(线程数,完成后需要执行的任务)

如:批量更新1000万条数据,数据更新完成后写入到ES中

/**
     * 批量更新1000万条数据,更新完成后将数据写入ES中
     * @param args
     */
    public static void main(String[] args) {

        CyclicBarrier cb = new CyclicBarrier(5,()->{
            System.out.println("更新完成,开始将数据写入到ES中");
        });
        for (int i = 1; i <=5 ; i++) {
            //拿到i
            new Thread(
        ()->{ System.out.println("当前"+Thread.currentThread().getName()+"数据库更新操作完成");
                        try {
                            cb.await();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    },String.valueOf(i)
            ).start();
        }
    }

  

3.Semaphore

信号量【抢车位(5个停车位,10个人来抢)】

限流中用的比较多

方法

semaphore.acquire();//获取资源,如果满了则等待,直到有资源释放为止

semaphore.release();//会将当前信号量释放,然后唤醒等待的线程

作用:多个共享资源互斥使用,【并发限流,控制最大的线程数】

/**
 * 10个车主抢5个车位
 */
public class SemaphoreTest {

    public static void main(String[] args) {
        //5个车位
        Semaphore semaphore = new Semaphore(5);
        //10个车主抢车位
        for (int i = 1; i <=10 ; i++) {
            new Thread(()->{
                try {
                    //获取车位
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"获得车位!");
                    //等待
                    TimeUnit.SECONDS.sleep(5);
                    //离开车位
                    System.out.println(Thread.currentThread().getName()+"离开车位!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }

}

  

4.读写锁

ReadWriteLock

public class ReadWriteLockTest {

    public static void main(String[] args) {
        MyCache cache = new MyCache();
        /**
         * 多线程下出现写多次问题,不能保证写只有一次
         */
        for (int i = 1; i <= 10; i++) {
            final String key = i + "";
            new Thread(() -> {
                cache.put(key, Thread.currentThread().getName());
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 10; i++) {
            final String key = i + "";
            new Thread(() -> {
                cache.get(key);
            }, String.valueOf(i)).start();
        }
    }

}

/**
 * 自定义缓存
 */
class MyCache {
    private volatile Map<String, Object> cache = new HashMap<>();
    //使用ReadWriteLock进行更加细粒度的控制
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    //写的过程
    public void put(String key, Object value) {
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            cache.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完成");
        } catch (Exception e) {

        } finally {
            readWriteLock.writeLock().unlock();
        }

    }

    //读的过程
    public void get(String key) {
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            Object o = cache.get(key);
            System.out.println(Thread.currentThread().getName() + "读取完成");

        } catch (Exception e) {

        } finally {
            readWriteLock.readLock().unlock();
        }

    }
}

  

5.阻塞队列

如果队里满了,写入时则会阻塞

如果队里是空的,读取时则会阻塞

BlockingQueue

 

 

什么情况下需要使用阻塞队列?

多线程并发处理,线程池

 

 

阻塞队列的操作:添加,移除

阻塞队列的API

1.抛出异常

2.不抛出异常

3.阻塞等待

4.超时等待

方式抛出异常有返回值,不抛出异常阻塞等待超时等待
添加 add offer[false] put offer(o,timeout,unit)
移除 remove poll[null] take pool(int,unit)
判断队列首个元素 element[NoSuchElementException] peek[null]    
/**
 * 添加删除元素有异常:add remove
 */
@Test
public void hasExc() {

    Queue queue = new ArrayBlockingQueue(3);
    System.out.println(queue.add(1));
    System.out.println(queue.add(2));
    System.out.println(queue.add(3));
    //java.lang.IllegalStateException: Queue full
    System.out.println("---------------------");
    //System.out.println(queue.add(4));


    System.out.println(queue.remove());
    System.out.println(queue.remove());
    System.out.println(queue.remove());
    System.out.println("*****************");
    System.out.println(queue.remove());
}

/**
 * 添加删除元素无异常 offer,poll
 */

@Test
public void noExc() {

    Queue queue = new ArrayBlockingQueue(3);
    System.out.println(queue.offer(1));
    System.out.println(queue.offer(2));
    System.out.println(queue.offer(3));
    System.out.println("---------------------");
    System.out.println(queue.offer(4));


     System.out.println(queue.poll());
     System.out.println(queue.poll());
     System.out.println(queue.poll());
     System.out.println("*****************");
     System.out.println(queue.poll());
}

/**
 * 添加删除元素阻塞 
 * put take
 * @throws InterruptedException
 */
@Test
public void block() throws InterruptedException {

    ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
    queue.put(1);
    queue.put(2);
    queue.put(3);
    System.out.println("---------------------");
    queue.put(4);


   System.out.println(queue.take());
   System.out.println(queue.take());
   System.out.println(queue.take());
   System.out.println("*****************");
   System.out.println(queue.take());
}

/**
 * 添加删除元素超时
 * offer(o,int,timeunit) poll(int,timeunit)
 * @throws InterruptedException
 */
@Test
public void noBlock() throws InterruptedException {

    ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
    System.out.println(queue.offer(1));
    System.out.println(queue.offer(2));
    System.out.println(queue.offer(3));
    System.out.println("---------------------");
    System.out.println(queue.offer(4,2,TimeUnit.SECONDS));


    System.out.println(queue.poll());
    System.out.println(queue.poll());
    System.out.println(queue.poll());
    System.out.println("*****************");
    System.out.println(queue.poll(2,TimeUnit.SECONDS));
}

/**
 * 获取队列首个元素
 * element 抛异常, peek 不抛异常
 * @throws InterruptedException
 */
@Test
public void obtainFirstObj() throws InterruptedException {

     ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        //为空时抛异常 NoSuchElementException
        System.out.println(queue.element());
        //为空时返回null
        System.out.println(queue.peek());
}
6.同步队列SynchronizedQueue
没有容量,放入的元素必须等待取出后才能接着放入元素。

/**
 * 放入元素A
 * 取出元素A
 * 放入元素B
 * 取出元素B
 * 放入元素C
 * 取出元素C
 */
BlockingQueue<String> strings = new SynchronousQueue<>();
new Thread(()->{

    try {
        System.out.println("放入元素A");
        strings.put("A");
        System.out.println("放入元素B");
        strings.put("B");
        System.out.println("放入元素C");
        strings.put("C");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
},"A").start();

new Thread(()->{

    try {
        System.out.println("取出元素A");
        strings.take();
        System.out.println("取出元素B");
        strings.take();
        System.out.println("取出元素C");
        strings.take();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
},"B").start();

  

线程池

1.池化技术

池化技术:对系统资源的优化。事先准备好一些资源,需要使用直接取

程序的运行本质:占用系统的资源!

线程池,连接池,内存池,对象池,字符串池

线程池的好处
1.降低资源的消耗
2.提高响应速度
3.方便管理

线程复用的好处:可以控制最大并发数,管理线程

 @Test
 public void exe() {
     //创建一个可伸缩的缓存线程池
     Executors.newCachedThreadPool();
     //创建一个固定线程池
     Executors.newFixedThreadPool(1);
     //创建一个线程执行器
     Executors.newSingleThreadExecutor();
     //创建周期性的线程池
     Executors.newScheduledThreadPool(1);
 }

 @Test
 public void exeCachedThreadPool() {
     //创建一个可伸缩的缓存线程池
     /*
     当前线程为: pool-1-thread-1
     当前线程为: pool-1-thread-1
     当前线程为: pool-1-thread-1
     当前线程为: pool-1-thread-3
     当前线程为: pool-1-thread-2
     当前线程为: pool-1-thread-4
     当前线程为: pool-1-thread-5
     当前线程为: pool-1-thread-6
     当前线程为: pool-1-thread-7
     当前线程为: pool-1-thread-8
      */
     ExecutorService executorService = Executors.newCachedThreadPool();
     for (int i = 0; i < 10; i++) {
         executorService.execute(() -> {
             System.out.println("当前线程为: " + Thread.currentThread().getName());
         });
     }
 }


 @Test
 public void exeSingleThreadExecutor() {
     //创建一个线程
     /**
      * 当前线程为: pool-1-thread-1
      *
      * 当前线程为: pool-1-thread-1
      * 当前线程为: pool-1-thread-1
      * 当前线程为: pool-1-thread-1
      * 当前线程为: pool-1-thread-1
      * 当前线程为: pool-1-thread-1
      * 当前线程为: pool-1-thread-1
      * 当前线程为: pool-1-thread-1
      * 当前线程为: pool-1-thread-1
      *
      * 当前线程为: pool-1-thread-1
      */
     ExecutorService executorService = Executors.newSingleThreadExecutor();
     for (int i = 0; i < 10; i++) {
         executorService.execute(() -> {
             System.out.println("当前线程为: " + Thread.currentThread().getName());
         });
     }
 }


 @Test
 public void exeFixedThreadPool() {
     //创建一个固定线程池
     /*
当前线程为: pool-1-thread-1
当前线程为: pool-1-thread-2
当前线程为: pool-1-thread-2
当前线程为: pool-1-thread-3
当前线程为: pool-1-thread-1
当前线程为: pool-1-thread-1
当前线程为: pool-1-thread-1
当前线程为: pool-1-thread-2
当前线程为: pool-1-thread-4
当前线程为: pool-1-thread-5

      */
     ExecutorService executorService = Executors.newFixedThreadPool(5);
     for (int i = 0; i < 10; i++) {
         executorService.execute(() -> {
             System.out.println("当前线程为: " + Thread.currentThread().getName());
         });
     }
 }

  

2.线程池参数

ThreadPoolExecutor
int corePoolSize:核心线程数
int maximumPoolSize:最大线程数【任务数>核心线程数+队列容量】
long keepAliveTime:超时后未调用就释放线程
TimeUnit unit:存活时间单位
BlockingQueue<Runnable> workQueue:队列
ThreadFactory threadFactory:线程工厂
RejectedExecutionHandler handler):拒绝策略

3.线程池存在问题

  FixedThreadPool 和 SingleThreadPool

  其允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM

  CacheThreadPool与ScheduleThreadPool

  允许创建的线程数量为Ingeter.MAX_VALUE,可能会创建大量的线程,从而导致OOM

4.自定义线程池

最大线程数:任务数>核心线程数+队列容量

拒绝策略:任务数>最大线程数+队列容量

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            1,//核心线程数
            2,//最大线程数[]
            3,//超时后释放
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2),//有界队列
            Executors.defaultThreadFactory(),
            //抛出异常条件:任务数> max+队列容量
            new ThreadPoolExecutor.AbortPolicy()//拒绝策略
    );

    for (int i = 0; i <6 ; i++) {
        threadPoolExecutor.execute(() -> {
            System.out.println("当前线程为: " + Thread.currentThread().getName());
        });
    }
}

  

5.四种拒绝策略[拒绝条件:任务数>最大线程数+队列容量]

AbortPolicy:默认拒绝策略,任务满了,不处理,抛出异常
CallerRunsPolicy:谁调用交给谁处理,线程池不处理
DiscardPolicy:队列满了,丢掉任务,不抛出异常
DiscardOldestPolicy:队列满了,尝试和最早的任务竞争【优化】,也不会抛出异常

6.最大线程池如何定义

IO密集型:大于IO线程数量【节假日时最大请求为1万,此时设置线程数大于1万】

CPU密集型:几核定义为几【Runtime.getRuntime().availableProcessors()】

四大函数式接口

函数式接口:只有一个方法的接口

Runnable接口

@FunctionalInterface

作用:简化编程模型

1.函数式接口

1.1Function<T, R>

@FunctionalInterface
public interface Function<T, R> {
 R apply(T t);//传入一个参数T,返回一个参数R
}
@Test
public void function() {
    //Function<T, R> 
    //new 时 需要传入一个 String 并指定返回值类型
    Function function = new Function<String,Object>() {
        @Override
        public String apply(String o) {
            return "------";
        }
    };
}
lambda进行简化

Function f = new Function<Stirng,Object>obj -> "------"
Function f = (str)->{return str}

  

1.2Predicate<T>

@Test
public void predicate() {
    //判断字符串是否为空
    Predicate<String> predicate = new Predicate<String>() {
        @Override
        public boolean test(String str) {
            return str.isEmpty();
        }
    };

}

@Test
public void predicateLambda() {
    //判断字符串是否为空
    Predicate<String> predicate = str -> str.isEmpty();
    predicate.test("a");

}
@Test
public void comsumer() {
    //只有参数,没有返回值
    Consumer<String> cons = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    cons.accept("aaa");
}
@Test
public void supplier() {
    //只有返回值,没有参数
    Supplier su = new Supplier() {
        @Override
        public Object get() {
            return 1;
        }
    };
    System.out.println(su.get());
}

  

 

接口类型说明参数/返回值lambda表达式 
Function<T,R> 输入一个参数,输出一个参数 T/R T->{return R}  
Predicate<T> 输入一个参数,对其进行判断 T/B T - >{return Boolean}  
Supplier<R> 没有参数,有返回值 R ()->{return R}  
Consumer<T> 只有输入,没有返回值 T T->{sout()}  

2.Stream流式计算

Person person1 = new Person("A", 12, 1);
Person person2 = new Person("B", 22, 2);
Person person3 = new Person("C", 33, 3);
Person person4 = new Person("D", 44, 4);
Person person5 = new Person("E", 55, 5);
Person person6 = new Person("F", 66, 6);

List<Person> people = Arrays.asList(person1, person2, person3, person4, person5, person6);
people.stream()//转化为Stream
        .filter(p-> p.getId()%2 ==0) //过滤
        .filter(p->p.getAge()>40)
        .map(p->p.getAge()+1)//操作
        .sorted((n1,n2)->n2.compareTo(n1))//排序
        .limit(1)
        .forEach(System.out::println);

  

3.ForkJoin

特点:工作窃取

原理:内部维护的是双端队列,A线程完成后,可以窃取B线程未完成的任务

ForkJoinTask:有两个实现子类

RecursiveAction:递归事件,没有返回值

RecursiveTask:递归任务,又返回值 task.get()

/**
 * 求和计算
 * 使用分支合并计算
 * 1.ForkJoinPool
 */
public class ForkJoinTest extends RecursiveTask<Long> {

    private static long startTime;
    private static long endTime;
    //临界值
    private static long tmp;
    private static long startValue;
    private static long endValue;
    private static long sum = 0;



    public ForkJoinTest(long startValue, long endValue) {
        this.startValue = startValue;
        this.endValue = endValue;
    }


    @Override
    protected Long compute() {
        if (endValue - startValue < tmp) {
            for (Long i = startValue; i < endValue; i++) {
                sum += i;
            }

        } else {
            long middle = (endValue - startValue) / 2;

            //1.拆分任务
            ForkJoinTest task1 = new ForkJoinTest(startValue, middle);
            ForkJoinTest task2 = new ForkJoinTest(middle + 1, endValue);

            //2.将任务压入到队列中
            task1.fork();
            task2.fork();
            //3.合并计算结果
            sum = task1.join() + task2.join();

        }

        return sum;
    }


        public static  void test1() {
            //1177
            startTime = System.currentTimeMillis();

            for (Long i = 0L; i < 10_0000_0000; i++) {
                sum += i;
            }
            endTime = System.currentTimeMillis();
            System.out.println("一共耗时: " + (endTime - startTime));
        }


        /**
         * 使用ForkJoinPool执行 ForkJoinTask 任务
         *
         * @throws ExecutionException
         * @throws InterruptedException
         */

        public static void test2() throws ExecutionException, InterruptedException {
            startTime = System.currentTimeMillis();
            ForkJoinPool forkJoinPool = new ForkJoinPool();
            ForkJoinTask task = new ForkJoinTest(0L, 10_0000_0000);
            //execute 阻塞的 执行任务  无返回值
            // forkJoinPool.execute(task);
            //异步的 提交任务 又返回值
            ForkJoinTask joinTask = forkJoinPool.submit(task);
            joinTask.get();//会发生阻塞
            endTime = System.currentTimeMillis();
            System.out.println("一共耗时: " + (endTime - startTime));
        }

        /**
         * 使用LongStream parallel进行并行流式计算
         */

        public static void test3() {
            startTime = System.currentTimeMillis();
          LongStream.rangeClosed(0,10_0000_0000).parallel().reduce(0,Long::sum);
            endTime = System.currentTimeMillis();
            System.out.println("一共耗时: " + (endTime - startTime));
        }


    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //test1();
        //test2();
        test3();
    }

}

  

使用LongStream进行并行流计算

  public static void test3() {
        startTime = System.currentTimeMillis();
        LongStream.rangeClosed(0,10_0000_0000).parallel().reduce(0,Long::sum);
        endTime = System.currentTimeMillis();
        System.out.println("一共耗时: " + (endTime - startTime));
    }

  

4.异步回调

1.异步执行

2.成功回调

3.失败回调

举例: CompletableFuture :

异步执行: runAsync(Runnable runnable)

成功回调:whenComplete(BiConsumer<? super T, ? super Throwable> action)

失败回调:BiConsumer(T,U) T:成功时返回值,U:失败时返回值

@Test
public void test1() throws ExecutionException, InterruptedException {
    //无返回值的异步执行
    CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("异步执行无返回值");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    System.out.println("任务执行……");
    completableFuture.get();//获取阻塞结果
}

@Test
public void test2() {
    //异步执行,又返回值结果
    CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("有返回值的异步任务执行");
        int i = 1 / 0;
        return 201;
    });
    completableFuture.whenComplete((t, u) -> {
        System.out.println("t->   " + t);//执行成功时获取的返回码 201
        System.out.println("u->   " + u);//执行失败时获取的返回码 400
    }).exceptionally((e) -> {
        System.out.println(e.getMessage());
        return 400;
    });
}

  

JMM

Java内存模型,不存在,它是一种约定

JMM中关于内存的约定:

1.线程解锁前,必须将共享变量立刻刷会主存

2.线程加锁前,必须将主存中的共享变量的最新值读取到工作内存中

3.加锁和解锁必须是同一把锁

 

 

Volatile

//此程序会出现的问题:不会停止
//使用 volatile关键字
private static  int num =0;
public static void main(String[] args) {

    new Thread(()->{
        while(num == 0){
            System.out.println("------");
        }
    }).start();

    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    num = 1;
}

  

volatile:Java提供的轻量级的同步机制

1.CPU的可见性

2.不保证原子性

num++:

  • 不是一个原子操作:底层会经过三步:1.读取num值,2.计算,3.写入num值

  • 如何解决

  • 使用原子类 AtomicInteger保证原子性:底层使用的是CAS操作

3.禁止指令重排

指令重排序时需要考虑其依赖性

源代码->编译器优化重排->指令并行也可能重排->内存系统也会重排

// private volatile int num = 0;
private volatile AtomicInteger num = new AtomicInteger();

@Test
//volatile不保证原子性测试
public void test() {

    //计算结果应该为100000,但是结果不正确
    for (int i = 1; i <= 50; i++) {
        new Thread(() -> {
            for (int j = 1; j <= 2000; j++) {
                add();
            }
        }).start();
    }


    while (Thread.activeCount() > 2) {  //main  gc
        Thread.yield();
    }
    System.out.println(Thread.currentThread().getName() + "   计算结果为: " + num);
}

/**
 * num++:
 * 不是一个原子操作:底层会经过三步:1.读取num值,2.计算,3.写入num值
 * 如何解决
 * 使用原子类 AtomicInteger保证原子性:底层使用的是CAS操作
 */

public void add() {

    //num++;
    num.getAndIncrement();
}

  

volatile如何保证禁重排序的?

通过内存屏障实现的

1.保证特定操作的执行顺序

2.保证某些变量的可见性

 

 

单例模式

饿汉式,懒汉式,静态内部类,枚举

[在DCL饿汉式中使用了volatile]

枚举Enum如何保证单例模式被破坏?

1.饿汉式

/**
 * 饿汉式
 * 1.保证构造器私有
 * 2.提供一个对象
 * 缺点:可能会浪费空间
 */
public class Hungry {

    private Hungry() {

    }

   private final static Hungry hungry = new Hungry();

    public static Hungry getInstance() {
        return hungry;
    }
}

  

1.2懒汉式

/**
 * 懒汉式
 * 特点:使用时创建
 */

public class LazyMan {

    private LazyMan() {
        System.out.println(Thread.currentThread().getName());
    }

    private static LazyMan lazyMan;
    //使用volatile关键字确保在对象创建过程中,不会进行对象创建的重排序
    private static volatile LazyMan lazyManV;

    //单线程不会出现问题

    /**
     * 多线程下会有多个对象被创建
     * @return
     */
    public static LazyMan getInstance() {
        if (lazyMan == null) {
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }

    /**
     * 使用dubble check进行检查:DCL
     * @return
     */
    public static LazyMan getInstance1(){
        if(lazyMan == null){
            synchronized (LazyMan.class){
                if(lazyMan == null){
                    //初始化不是一个原子操作
                    /**
                     * 1.分配内存空间
                     * 2.执行构造方法,初始化对象
                     * 3.把这个对象指向这个空间
                     * 可能的过程为:123 ,也可能为132  
                     * 在132过程中,如果这个时候如果另一个线程对其进行访问,就会出现对象已经存在,但是在使用时出现空指针问题
                     * 所以此时需要使用volatile关键字进行禁止指令重排序
                     */
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(LazyMan::getInstance,String.valueOf(i)).start();
            new Thread(LazyMan::getInstance1,String.valueOf(i)).start();
        }

    }
}

  

1.3内部静态类

/**
 * 内部类实现单例模式
 */
public class Outter {

    /**
     * 构造器私有,确保对象单例
     */
    private Outter() {

    }
    public Outter getInstance(){
        return Inner.OUTTER;
    }

    public static class Inner {
        private static final Outter OUTTER = new Outter();
    }

}

  

1.4使用反射破坏单例模式

1.4.1饿汉式

/**
 * 饿汉式
 * 1.保证构造器私有
 * 2.提供一个对象
 * 缺点:可能会浪费空间
 */
public class Hungry {

    private Hungry() {

        /**
         * 解决:在使用反射进行对象创建时,抛出异常
         */
       synchronized (Hungry.class){
           if(hungry != null){
               throw  new RuntimeException("禁止使用反射创建对象!!!");
           }
       }
    }
    private final static Hungry hungry = new Hungry();

    public static Hungry getInstance() {
        return hungry;
    }
    public static void main1(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //使用反射破坏单例模式
        Hungry hungry = Hungry.getInstance();
        Constructor<Hungry> constructor = Hungry.class.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        Hungry hungry1 = constructor.newInstance();
        System.out.println(hungry == hungry1);//false
    }
}

  

1.4.2懒汉式

/**
 * 懒汉式
 * 特点:使用时创建
 */

public class LazyMan {

    private static boolean proInstance =false;
    private LazyMan() {
    synchronized (LazyMan.class){
        if(proInstance == false){
            proInstance = true;
        }else{
            throw new RuntimeException("禁止使用发射创建对象!");
        }
    }
}

    private static LazyMan lazyMan;
    //使用volatile关键字确保在对象创建过程中,不会进行对象创建的重排序
    private static volatile LazyMan lazyManV;

    //单线程不会出现问题

    /**
     * 多线程下会有多个对象被创建
     * @return
     */
    public static LazyMan getInstance() {
        if (lazyMan == null) {
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }

    /**
     * 使用dubble check进行检查:DCL
     * @return
     */
    public static LazyMan getInstance1(){
        if(lazyMan == null){
            synchronized (LazyMan.class){
                if(lazyMan == null){
                    //初始化不是一个原子操作
                    /**
                     * 1.分配内存空间
                     * 2.执行构造方法,初始化对象
                     * 3.把这个对象指向这个空间
                     * 可能的过程为:123 ,也可能为132
                     * 在132过程中,如果这个时候如果另一个线程对其进行访问,就会出现对象已经存在,但是在使用时出现空指针问题
                     * 所以此时需要使用volatile关键字进行禁止指令重排序
                     */
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }

    public static void main1(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //使用反射破坏懒汉式单例
        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        LazyMan lazyMan1 = constructor.newInstance();
        LazyMan lazyMan2 = constructor.newInstance();
        System.out.println(lazyMan1 == lazyMan2);//false

    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //使用反射获取指定的字段
        Field proInstance = LazyMan.class.getDeclaredField("proInstance");
        proInstance.setAccessible(false);
        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        LazyMan lazyMan1 = constructor.newInstance();
        proInstance.set(lazyMan1,false);
        LazyMan lazyMan2 = constructor.newInstance();
        System.out.println(lazyMan1 == lazyMan2);//false

    }

  

1.5Enum中的解决方式

if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
public enum EnumSingle {

    INSTANCE;

    public EnumSingle getInstance(){
        return INSTANCE;
    }

}
class EnumT{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingle instance1 = EnumSingle.INSTANCE;
        EnumSingle instance2 = EnumSingle.INSTANCE;
        System.out.println(instance1 == instance2);//true

        //使用反射破坏单例
        //java.lang.NoSuchMethodException
        //Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
        
        //java.lang.IllegalArgumentException: Cannot reflectively create enum objects
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSingle enumSingle = declaredConstructor.newInstance();
        EnumSingle enumSingle1 = declaredConstructor.newInstance();
        System.out.println(enumSingle== enumSingle1) ;

    }
}

  

CAS机制

CAS:compareandset:CPU并发原语

如果符合期望的值就更新,否则就不更新

public static void main(String[] args) {
    AtomicInteger integer = new AtomicInteger(1);
    //int expect, int update
    System.out.println(integer.compareAndSet(1, 2));//true
    System.out.println(integer.get());
    System.out.println(integer.compareAndSet(1, 2));//false
    System.out.println(integer.get());
}

 

 

Unsafe类

java无法操作内存,但是可以通过调用native实现对内存的操作,这个类就是操作内存的

private static final long valueOffset;

static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}

private volatile int value;
 

  

CAS的ABA问题

CAS:比较当前值与主内存中方的值,如果这个值是期望的值,则执行操作;如果不是期望的值,则一直循环。

缺点:

1.循环耗时

2.一次性只能保证一个共享变量的原子性

3.ABA问题【乐观锁】

原子引用

带版本号的原子操作

AtomicReference类

/**
 * 解决CAS-ABA 问题方法:AtomicStampedReference
 * @param args
 */
public static void main(String[] args) {
    AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(1,666);
    new Thread(()->{
        //获取版本号
        int stamp = reference.getStamp();
        System.out.println("A1 版本号" + stamp);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(reference.compareAndSet(1, 2, reference.getStamp(), reference.getStamp() + 1));
        System.out.println("A2版本号"+ reference.getStamp());

        System.out.println(reference.compareAndSet(2, 1, reference.getStamp(), reference.getStamp() + 1));
        System.out.println("A3版本号"+ reference.getStamp());
    },"A").start();
    new Thread(()->{
        //获取版本号
        int stamp = reference.getStamp();
        System.out.println("B1 版本号" + stamp);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(reference.compareAndSet(1, 3, reference.getStamp(), reference.getStamp() + 1));
        System.out.println("B2版本号"+ reference.getStamp());

    },"B").start();


}

  

1.公平锁,非公平锁

公平锁:公平,不可以插队 new ReentrantLock(){new NonfairSync()}

非公平锁:不公平,允许插队(默认都是非公平)new ReentrantLock(boolean fair){new FairSync()}

2.可重入锁

所有的锁都是可重入锁【递归锁】,即获取外部的锁,就会自动获得内部的锁

/**
 * 测试可重入锁
 */
public class ReentrantLockTest {


    public static void main(String[] args) {
        Book book = new Book();
        /**
         * 当A、B开始调用read方法,总是A -> read() ->write()
         */
        new Thread(book::read, "A").start();
        new Thread(book::read, "B").start();
        new Thread(book::read1, "C").start();
        new Thread(book::read1, "D").start();
    }


}

class Book {
    public synchronized void read() {
        System.out.println(Thread.currentThread().getName() + " read()");
        //此时锁未释放,还存在锁
        write();
    }

    public synchronized void write() {
        System.out.println(Thread.currentThread().getName() + " write()");
    }

    //非公平锁
    //锁要成对出现: lock.lock() lock.unlock() ,否则会出现死锁
    Lock lock = new ReentrantLock();

    public synchronized void read1() {
        lock.lock();
        //lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " read1()");
            write1();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
           // lock.unlock();
        }

    }

    public synchronized void write1() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " write1()");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

  

3.自旋锁

Spinlock:

do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

自定义自旋锁

/**
 * 自定义自旋锁
 */
public class CustomSpinlock {

    private AtomicReference<Thread> reference = new AtomicReference<>();

    public void lock(){
        Thread currentThread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"通过自旋加锁");
        while(!reference.compareAndSet(null,currentThread)){
           // System.out.println(Thread.currentThread().getName()+"  lock() ...");
        }

    }
    public void unlock(){
        Thread currentThread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"释放锁 unlock()");
        reference.compareAndSet(currentThread,null);
    }

}

  

测试自定义的自旋锁

public class CustomSpinlockTest {
    public static void main(String[] args) {
        /**
         * Lock lock = new ReentrantLock();
         *  lock.lock();
         *  lock.unlock();
         *
         *
         * T1通过自旋加锁
         * T2通过自旋加锁
         * T1释放锁 unlock()
         * T2释放锁 unlock()
         */
        CustomSpinlock customSpinlock = new CustomSpinlock();
        new Thread(() -> {
            customSpinlock.lock();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                customSpinlock.unlock();
            }

        }, "T1").start();
        new Thread(() -> {
            customSpinlock.lock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                customSpinlock.unlock();
            }
        }, "T2").start();

    }

}

  

4.死锁

 

 

模拟死锁出现

public class DeadLockDemo {

    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";
        new Thread(new MyDeadLock(lockA,lockB),"T1").start();
        new Thread(new MyDeadLock(lockB,lockA),"T2").start();
    }
}

class MyDeadLock implements  Runnable{
    private String lockA;
    private String lockB;

    public MyDeadLock(String lockA, String lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    @Override
    public void run() {
        synchronized (lockA){
            System.out.println(Thread.currentThread().getName() + " lock: " + lockA + "获取 " + lockB);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lockB){
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " lock: " + lockB + "获取 " + lockA);
            }
        }
    }
}

  

死锁解决

1.使用jps -l定位进程号

2.使用jstack 进程号查看死锁信息 [Found 1 deadlock.]

posted @ 2021-03-07 00:36  叮叮007  阅读(171)  评论(0编辑  收藏  举报