文章目录

  • 1JUC
  • 2回顾多线程知识
  • 3Lock锁(重点)
  • 4Lock锁
  • 5JUC版的生产者与消费者问题(虚假唤醒)
  • 6有序线程
  • 7八锁问题
  • 8CopyOnWriteArrayList(读写复制)
  • 9Set并发问题解决方案
  • 10HashMap不安全解决方案
  • 11线程计数器
    • 11.1线程加法计数器(CyclicBarrier)
    • 11.2线程减法计数器(CountDownLatch)
  • 13读共享锁(写独占锁)(MyCache)
  • 14(BlockingQueue四组API)
  • 15同步队列(SynchronousQueue、不存储元素)
  • 16线程池(ThreadPoolExecutor)
    • 查看电脑CPU核数的代码
  • 17四大函数式接口
    • Function(输入值和返回值相同)
    • Predicate(返回布尔值、判断字符串是否为空)
    • Consumer(只有输入值没有返回值)
    • Supplier()
  • 18链式编程(Stream流式计算)
  • 19ForkJoin
    • 三种处理线程的方式
  • 20异步回调(Future)
  • 21理解JMM(Volatile)
  • 22Volatile可见性及非原子性验证
    • 不保证原子性
  • 23指令重排详解
  • 24单例模式(饿汉模式和懒汉模式)
  • 25深入理解CAS
  • 26原子引用解决ABA问题(需要引入原子引用-27节提到)
    • 26.1ABA问题
    • 26.2原子引用解决ABA问题
  • 27可重入锁
  • 28自旋锁
    • 测试自旋锁
  • 29死锁排查(jps)
    • 解决问题
  • 30乐观锁、悲观锁(无内容)

1JUC

2回顾多线程知识

进程和线程:
进程:一个进程可以包含多个线程,至少是一个线程,java默认2个线程——main、GC(垃圾回收)
线程:开了一个软件,写字的时候也会有自动保存的线程在进行,Thread、Runnable、Callable
java开启不了线程,java操作的是底层的C++,java无法操作,用的是虚拟机
并发与并行:
并发:多线程操作同一个资源(假设cpu只有一核的时候,模拟多线程,快速交替处理线程)
并行:CPU多核情况下才有,多个线程同时执行并发编程的本质:充分利用电脑的CPU
线程有几种状态:6种:new(创建)、runnable(运行)、blocked(阻塞)、wait(等待)、timed_waiting(超时等待)
terminated(终止)wait与sleep的区别:
1.来自不同的类——wait(Object)、sleep(Thread)
2.关于锁——wait会释放锁,而sleep不会释放
3.适用范围不一样——wait必须在同步代码块中执行,sleep则不用
4.w捕获异常——wait不需要捕获异常、sleep需要捕获异常

3Lock锁(重点)

传统Synchronized解决有顺序卖票问题

package JUC;
/*基本的卖票的例子
线程是一个单独的资源类
* */
public class Demo02SaleTicket {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(()->{for (int i = 0; i < 60; i++) {ticket.sale();}},"A").start();new Thread(()->{for (int i = 0; i < 60; i++) {ticket.sale();}},"B").start();new Thread(()->{for (int i = 0; i < 60; i++) {ticket.sale();}},"C").start();}
}class Ticket{private int num=30;public synchronized void sale(){if (num>0){System.out.println(Thread.currentThread().getName()+"卖出了第"+(num--)+"票,剩余"+num);}}
}

4Lock锁

package JUC;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Demo03Lock {public static void main(String[] args) {Ticket1 ticket1 = new Ticket1();}
}//Lock锁————三步骤——1.new ReentrantLock 2.加锁 3.解锁
class Ticket1{private int num=30;//ReentrantLock---java默认非公平锁,也就是默认可以插队(比较合理,3秒的不需要等待3小时的线程)Lock lock=new ReentrantLock();public void sale(){lock.lock();//加锁try {//业务代码if (num>0){System.out.println(Thread.currentThread().getName()+"卖出了第"+(num--)+"票,剩余"+num);}} catch (Exception e) {e.printStackTrace();}finally {lock.unlock();//解锁}}}

5JUC版的生产者与消费者问题(虚假唤醒)

package JUC;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*JUC版的生产者与消费者问题
通过Lock可以找到Condition
以下的是无序的随机的状态结果,JUC的优势还没有体现出来
ReentrantLock是可重入的意思
* */
public class Demo05JUC1 {public static void main(String[] args) {Date1 date1 = new Date1();new Thread(()->{for (int i = 0; i < 10; i++) {try {date1.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {date1.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {date1.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {date1.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();}}
class Date1{private int num=0;Lock lock=new ReentrantLock();Condition condition = lock.newCondition();public  void increment() throws InterruptedException {lock.lock();try {while (num!=0){//等待//this.wait();JUC之前普通的condition.await();}num++;System.out.println(Thread.currentThread().getName()+"=="+num);//通知线程B,我+1完毕了this.notifyAll();JUC之前普通的condition.signalAll();//唤醒全部} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public  void decrement() throws InterruptedException {lock.lock();try {while (num==0){//等待//this.wait();condition.await();}num--;System.out.println(Thread.currentThread().getName()+"=="+num);//通知线程B,我-1完毕了 JUC之前的this.notifyAll();condition.signalAll();//唤醒全部} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}
}

6有序线程

package JUC;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*实现生产者与消费者的有序JUC执行
三条线程按照循环顺序执行
* */
public class Demo06JUC2 {public static void main(String[] args) {new Thread(()->{},"A").start();new Thread(()->{},"B").start();new Thread(()->{},"C").start();}
}//资源类
class Date3{private Lock lock=new ReentrantLock();private Condition condition = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();private int num=1;public void print1(){lock.lock();try {//业务代码,判断-执行-通知if (num!=1){condition.await();}System.out.println(Thread.currentThread().getName()+"1111");//通知唤醒num=2;condition2.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void print2(){lock.lock();try {if (num!=2){condition2.await();}System.out.println(Thread.currentThread().getName()+"2222");num=3;condition3.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void print3(){lock.lock();try {if (num!=3){condition3.await();}System.out.println(Thread.currentThread().getName()+"3333");num=1;condition.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}

7八锁问题

package JUC;import java.util.concurrent.TimeUnit;/*什么是锁,锁的对象是谁——查看自己的收藏笔记
8锁,就是关于锁的8个问题
1.标准情况下,线程先执行哪个?————先发短信再打电话(原因:锁的存在)
2.发短信延迟4秒的情况下————还是先短信再电话,先执行发短信,因为有同步锁
3.增加了一个普通方法后,是执行发短信还是hello,限制性普通方法,普通方法不受锁的限制
4.两个对象的情况下,先执行发短信还是打电话——————打电话,因为两把锁不一样,打电话的锁有延迟
5.静态方法的时候,两个线程先执行哪个?——————加了static以后锁的就是class对象,类的模板只有一个所以和原先锁的是对象没有关系* */
public class Demo07suo1 {public static void main(String[] args) {Phone phone = new Phone();Phone phone1 = new Phone();//第一条线程new Thread(()->{phone.send();},"A").start();//A线程睡眠try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}//第二条线程new Thread(()->{phone1.call();},"B").start();}
}
//资源类
class Phone{public  static synchronized void send(){        //synchronized锁的是方法的调用者,两个功能都是phone的调用,锁的对象是phonetry {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("发短信");}public  synchronized   void call(){System.out.println("打电话");}
}

8CopyOnWriteArrayList(读写复制)

(ConcurrentModificationException并发修改异常,不能一起修改)

package JUC;import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;/*.ConcurrentModificationException并发修改异常,不能一起修改
并发下ArrayList不安全————结局方案:
1.List<String> list1 =new Vector<>();
2. List<String> list1 = Collections.synchronizedList(new ArrayList<>());
3. List<String> list1 = new CopyOnWriteArrayList<>();它比Vector效率高原因在于Vector用到了synchronized,导致了效率低
4.
* */
public class Demo11Unsafe {public static void main(String[] args) {List<String> list1 = new CopyOnWriteArrayList<>();/*   CopyOnWriteArrayList写入时复制COW计算机程序设计领域的一种优化策略在写入的时候复制一份,出现覆盖的问题,造成数据问题*/for (int i = 0; i < 10; i++) {list1.add(UUID.randomUUID().toString().substring(0,5));//生成随机字符串new Thread(()->{System.out.println(list1);},String.valueOf(i)).start();//添加十条线程}}
}

9Set并发问题解决方案

package JUC;import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;/*Set还是会出现并发问题
HashSet的底层就是hashmap
add set 本质就是map ,map key是无法重复的
解决方案:
1.Set<String> set = Collections.synchronizedSet(new HashSet<>());
2.Set<String> set =new CopyOnWriteArraySet<>();
3.
* */
public class Demo12SetTest {public static void main(String[] args) {// Set<String> set = Collections.synchronizedSet(new HashSet<>());new HashSet<>();Set<String> set =new CopyOnWriteArraySet<>();for (int i = 1; i < 30; i++) {new Thread(()->{set.add(UUID.randomUUID().toString().substring(0,5));System.out.println(set);},String.valueOf(i)).start();}}
}

10HashMap不安全解决方案

package JUC;import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;/*HashMap本质也不是安全的
解决方法:
1.Map<String , String > map1 = new ConcurrentHashMap<>();
2.ConcurrentHashMap原理
* */
public class Demo13HashMapTest {public static void main(String[] args) {Map<String , String > map = new HashMap<>();Map<String , String > map1 = new ConcurrentHashMap<>();for (int i = 1; i <= 30; i++) {new Thread(()->{map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));System.out.println(map);},String.valueOf(i)).start();}}
}

11线程计数器

11.1线程加法计数器(CyclicBarrier)

package JUC;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;/*加法计数器
线程达到一定数量的时候开始执行操作,集齐7颗龙珠就可以召唤神龙
* */
public class Demo15CyclicBarrier {public static void main(String[] args) {CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {System.out.println("完成加法计数");});for (int i = 1; i <= 7; i++) {final int a=i;new Thread(()->{System.out.println(Thread.currentThread().getName()+"收集"+a);try {cyclicBarrier.await();//等待} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}).start();}}
}

11.2线程减法计数器(CountDownLatch)

package JUC;import java.util.concurrent.CountDownLatch;/*JUC常用三大类:一、
*计数器(减法计数器)
*
* */
public class Demo14CountDownLatch {public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(6);//总数是6,必须要执行任务的时候再使用for (int i = 1; i <= 6; i++) {new Thread(()->{System.out.println(Thread.currentThread().getName()+"go");countDownLatch.countDown();//数量-1},String.valueOf(i)).start();}countDownLatch.await();//等待计数器归0,然后再向下执行System.out.println("close");}
}

#12线程等待释放离开、等待一定时间停车位释放(Semaphore)

package JUC;import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;/*信号量
线程数量:停车位,有限的线程分给几个对象相互占用,限流————控制线程数
semaphore.acquire()————获得,假设线程满了就等待释放
semaphore.release()————释放
* */
public class Demo16Semaphore {public static void main(String[] args) {//线程数量:停车位Semaphore semaphore = new Semaphore(3);for (int i = 1; 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) {e.printStackTrace();}finally {semaphore.release();//释放}},String.valueOf(i)).start();}}
}

13读共享锁(写独占锁)(MyCache)

package JUC;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;/*读写锁
读锁(共享锁)多个线程可以同时占有
写锁(独占锁)一次只能被一个线程锁占用
* */
public class Demo17ReentrantReadWriteLock {public static void main(String[] args) {MyCache myCache = new MyCache();//写入的操作for (int i = 1; i <= 5; i++) {final int a=i;//lambda表达式无法访问外部的变量new Thread(()->{myCache.put(a+"",a+"");},String.valueOf(i)).start();}for (int i = 1; i <= 5; i++) {final int a=i;//lambda表达式无法访问外部的变量new Thread(()->{myCache.get(a+"");},String.valueOf(i)).start();}}}
class MyCache{private volatile Map<String ,Object> map=new HashMap<>();private ReadWriteLock readWriteLock=  new ReentrantReadWriteLock();  //读写锁创建//存,写public void put(String key,Object value){readWriteLock.writeLock().lock();try {System.out.println(Thread.currentThread().getName()+"写入"+key);map.put(key,value);System.out.println(Thread.currentThread().getName()+"写入完毕");} catch (Exception e) {e.printStackTrace();} finally {readWriteLock.writeLock().unlock();}}//取,读public void get(String key){readWriteLock.readLock().lock();try {System.out.println(Thread.currentThread().getName()+"读取"+key);Object o = map.get(key);System.out.println(Thread.currentThread().getName()+"读取完毕");} catch (Exception e) {e.printStackTrace();} finally {readWriteLock.readLock().unlock();}}
}

14(BlockingQueue四组API)

添加、删除、队列首元素、超时等待等等方法

package JUC;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;/*BlockingQueue四组API,queue是队列的意思
添加、删除、队列首元素、超市等待等等方法
* */
public class Demo18BlockingQueue {public static void main(String[] args) {/*   test1();test2();*/try {test3();} catch (InterruptedException e) {e.printStackTrace();}}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.element());// System.out.println(blockingQueue.add("d"));//取出元素System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());//System.out.println(blockingQueue.remove());.NoSuchElementException异常// System.out.println(blockingQueue.remove());}public static void test2(){//满了不会抛出异常ArrayBlockingQueue<Object> 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"));//false,不会抛出异常System.out.println(blockingQueue.peek());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());//不会阻塞,直接显示空的值}public static void test3() throws InterruptedException {ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);blockingQueue.put("a");blockingQueue.put("b");blockingQueue.put("c");blockingQueue.put("d");//现在的这种情况就是一直的等待,因为已经满了,所以要等待移除出去以后才可以开始添加blockingQueue.take();blockingQueue.take();blockingQueue.take();blockingQueue.take();//没有元素的时候也是一直阻塞等待的}public static void test4() throws InterruptedException {ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);blockingQueue.offer("a");blockingQueue.offer("b");blockingQueue.offer("c");blockingQueue.offer("d",3, TimeUnit.SECONDS);//超时等待,超过3秒就退出blockingQueue.poll(2,TimeUnit.SECONDS);blockingQueue.poll(2,TimeUnit.SECONDS);blockingQueue.poll(2,TimeUnit.SECONDS);blockingQueue.poll(2,TimeUnit.SECONDS);//取出,超过两秒就退出}}

15同步队列(SynchronousQueue、不存储元素)

package JUC;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/*同步队列
和其他的BlockingQueue不一样,SynchronousQueue不存储元素
put了一个值,必须从里面先take出来,否则不能再put进去
* */
public class Demo19SynchronousQueue {public static void main(String[] args) {BlockingQueue<String > blockingQueue = new SynchronousQueue<>();//同步队列new Thread(()->{try {System.out.println(Thread.currentThread().getName()+"put 1");blockingQueue.put("1");System.out.println(Thread.currentThread().getName()+"put 2");blockingQueue.put("2");System.out.println(Thread.currentThread().getName()+"put 3");blockingQueue.put("3");} catch (Exception e) {e.printStackTrace();} finally {}},"A").start();new Thread(()->{try {TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"=="+blockingQueue.take());TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"=="+blockingQueue.take());TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"=="+blockingQueue.take());} catch (InterruptedException e) {e.printStackTrace();}},"B").start();}
}

16线程池(ThreadPoolExecutor)

/*线程池(重点)
线程池的好处:
1.降低资源的消耗
2.提高相应的速度
3.方便管理
线程三大方法、7大参数、4种拒绝策略(重点!!!)
3大方法:
以下Executors三大方法
7大参数:
ThreadPoolExecutor线程池执行者包含的7个参数
4种拒绝策略:
1.new ThreadPoolExecutor.AbortPolicy() 人满了,抛出异常
2.new ThreadPoolExecutor.CallerRunsPolicy(),main的线程执行,哪来的去哪里
3.new ThreadPoolExecutor.DiscardPolicy()线程满了,丢掉任务,不会抛出异常
4.new ThreadPoolExecutor.DiscardOldestPolicy());线程满了先和最早的线程去竞争,然后争不过的额时候、丢掉任务,不会抛出异常
使用了线程池以后就要用线程池来创建线程

线程池的大小怎么去设置:(两种)
CPU密集型:电脑是几核的就用几来定义最大线程数
IO密集型:当你的电脑有大型的任务的时候,设置线程大于IO密集型任务的个数(IO)十分占用资源

  • */
package JUC;import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Demo20pool {public static void main(String[] args) {//ExecutorService threadPool = Executors.newSingleThreadExecutor();//单线程//ExecutorService threadPool = Executors.newFixedThreadPool(5);//设定固定的线程数//ExecutorService threadPool = Executors.newCachedThreadPool();//可变化的线程数量,遇强则强,遇弱则弱ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,5,3,TimeUnit.SECONDS,new LinkedBlockingDeque<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy());//两个窗口、最多5个窗口、等待3秒、候客区3个、默认线程、拒绝策略(四种)try {for (int i = 0; i < 9; i++) {threadPoolExecutor.execute(()->{System.out.println(Thread.currentThread().getName()+" ok");});}} catch (Exception e) {e.printStackTrace();} finally {//线程池用完需要关闭threadPoolExecutor.shutdown();}}
}

查看电脑CPU核数的代码

package ceshi;public class CPU {public static void main(String[] args) {System.out.println(Runtime.getRuntime().availableProcessors());}
}

17四大函数式接口

函数式四大接口:Consumer、Function、Predicate、Supplier
程序员必备技能:lambda表达式、链式编程、函数式接口、Stream流式计算

Function(输入值和返回值相同)

package JUC;import java.util.function.Function;/*四大函数式接口:Function
* */
public class Demo21Function {public static void main(String[] args) {//工具类:输入输出的值相等Function function = new Function<String,String>() {@Overridepublic String apply(String str) {return str;}};System.out.println(function.apply("asd"));Function<String , String > function1 = (str)->{return str;};//最简化lambda表达式}
}

Predicate(返回布尔值、判断字符串是否为空)

package JUC;import java.util.function.Predicate;
/*四大函数式接口:Predicate
断定型接口:有一个输入参数、返回值只能是布尔值
* */
public class Demo22Predicate {public static void main(String[] args) {//判断字符串是否为空/*   Predicate<String> predicate = new Predicate<String>() {@Overridepublic boolean test(String  o) {return o.isEmpty();}};*/Predicate<String> predicate = (str)->{return str.isEmpty();};//lambda表达式System.out.println(predicate.test("asd"));}
}

Consumer(只有输入值没有返回值)

package JUC;import java.util.function.Consumer;/*消费型接口:只有输入值,没有返回值
* */
public class Demo23Consumer {public static void main(String[] args) {/* Consumer<String > consumer = new Consumer<String>() {@Overridepublic void accept(String  o) {System.out.println(o);}};*/Consumer<String > consumer =(o)->{System.out.println(o);};consumer.accept("byug");}
}

Supplier()

package JUC;import java.util.function.Supplier;/*供给型接口:没有参数、只有返回值
* */
public class Demo24Supplier {public static void main(String[] args) {/* Supplier<Integer> objectSupplier = new Supplier<Integer>() {@Overridepublic Integer get() {System.out.println("get()");return 1024;}};*/Supplier<Integer> supplier =()->{System.out.println("get()");return 1024;};System.out.println(supplier.get());}
}

18链式编程(Stream流式计算)

package JUC;import java.util.Arrays;
import java.util.List;/*链式编程
* */
public class Demo25 {public static void main(String[] args) {User user = new User(1,"a",21);User user2 = new User(2,"b",23);User user3 = new User(3,"c",45);User user4 = new User(4,"d",48);//集合就是存储List<User> list = Arrays.asList(user, user2, user3, user4);//计算交给Stream//lambda表达式、链式编程、函数式接口、Stream流式计算//以下就是链式编程list.stream().filter(u->{return u.getId()%2==0;}).filter(u->{return u.getAge()>23;}).map(u->{return u.getName().toUpperCase();}).sorted((uu1,uu2)->{return uu2.compareTo(uu1);}).limit(1).forEach(System.out::println);}
}
class User{int id;String name;int age;public User() {}public User(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}
}

19ForkJoin

特点:并行执行任务、提高效率、大数量的时候使用(注意有弊端,必须大数据的时候去使用)
ForkJoin特点:工作窃取,如图所示,当A没有完成任务的时候,B线程已经完成任务,B线程就会去窃取A线程的任务,从而达到有效利用的目的。
ForkJoin缺点:因为是双端队列,所以可能AB会同时去抢任务。所以必须大量数据的时候去使用
双端队列:可以从上往下执行,也可以从下往上执行

三种处理线程的方式

package JUC;import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;/*线程拆分
*
* */
public class Demo26ForkJoin {public static void main(String[] args) throws ExecutionException, InterruptedException {//            test1();//2000
//            test2();//2000test3();//200}//测试一public static void test1(){long sum=0L;long start=System.currentTimeMillis();for (long i = 1L; i <= 10_0000_0000; i++) {sum+=i;}long end=System.currentTimeMillis();System.out.println("和为"+sum+",花掉的时间为:"+(end-start));}//测试二public static void test2() throws ExecutionException, InterruptedException {long start=System.currentTimeMillis();ForkJoinPool forkJoinPool = new ForkJoinPool();ForkJoinDemo task = new ForkJoinDemo(0L,10_0000_0000L);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();//Stream并行流           rangeClosed(],parallel是并行的意思,long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);long end=System.currentTimeMillis();System.out.println("和为"+sum+",花掉的时间为:"+(end-start));}}
/*
1.forkjoin通过它来执行
2.计算任务forkjoinpool.execute(ForkjoinTest task)
* */
class ForkJoinDemo extends RecursiveTask<Long> {private Long start;private Long end;//临界值private Long temp=100L;public ForkJoinDemo(Long start, Long end) {this.start = start;this.end = end;}public void test(){}//计算方法@Overrideprotected Long compute() {if ((end-start)>temp){//分值计算Long sum=0L;for (Long i = start; i <= end; i++) {sum += i;}return sum;}else{long middle = (start + end) / 2;//中间值ForkJoinDemo task1 = new ForkJoinDemo(start, middle);task1.fork();//拆分任务,把任务压入线程队列ForkJoinDemo task2= new ForkJoinDemo(middle+1, end);task2.fork();//拆分任务,把任务压入线程队列return task1.join()+task2.join();}}
}

20异步回调(Future)

Future:对将来的某个时间的结果进行建模

package JUC;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;/*异步调用Future
Ajax:不需要等待一段时间得到前面的线程结果,而后可以直接去进行别的任务
异步执行
成功回调
失败回调
* */
public class Demo27 {public static void main(String[] args) throws ExecutionException, InterruptedException {/*    //发起一个请求    runAsync(异步)//以下是没有返回值的runAsync异步回调CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"runAsync=>Void");});System.out.println("1111");completableFuture.get();//获取阻塞执行结果*///以下是有返回值的supplyAsync异步回调//ajax,成功和失败的回调,如果失败返回的是错误的信息CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName()+"supplyAsync=>Integer");int i=10/0;return 1024;});System.out.println(completableFuture.whenComplete((t, u) -> {System.out.println("t" + t);//正常执行返回结果System.out.println("u" + u);//有错误的时候返回的错误信息}).exceptionally((e) -> {System.out.println(e.getMessage());return 100;//可以获取到错误的返回信息}).get());}
}

21理解JMM(Volatile)

Volatile:java虚拟机提供轻量级的同步机制
1.保证可见性
2.不保证原子性
3.禁止指令重排
JMM:java内存模型,不存在的东西,概念、约定
作用:保证线程的安全
关于JMM的一些同步约定:
1.线程加锁前,必须把共享变量刷回主存(内存里面有一份,线程拷贝得出结果以后刷回主存)
2.线程解锁前,必须读取主存中的最新值到工作内存中
3.加锁和解锁必须是同一把锁
工作内存、主内存八种操作,必须成对存在

package JUC;import java.util.concurrent.TimeUnit;public class Demo28JMM {private static int num=0;public static void main(String[] args) {//main主线程new Thread(()->{//线程1while (num==0){}}).start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}num=1;System.out.println(num);}
}

运行结果是1,但是程序没有停止
需要让A线程知道主内存中的值已经发生变化,这个时候就要用到Volatile

22Volatile可见性及非原子性验证

Volatile不保证原子性
原子性:不可分割
线程A在执行任务的时候,不能被打扰的,也不能被分割,要么同时成功,要么同时失败

package JUC;
/*不保证原子性
* */
public class Demo29Volatile {private  static int num=0;//volatile加上以后不能保证20000次执行结果,所以volatile不保证原子性!!public static  void add(){//synchronized加上以后可以保证20000次执行,num++;//num++本身就不是一个原子性操作}public static void main(String[] args) {//理论上的结果为20000for (int i = 1; i <= 20; i++) {new Thread(()->{for (int i1 = 1; i1 <= 1000; i1++) {add();}}).start();}while (Thread.activeCount()>2){//activeCount是还存活的线程的数量,除开main和gc以外才可以0Thread.yield();//礼让}System.out.println(Thread.currentThread().getName()+" "+num);}
}

不保证原子性

package JUC;import java.util.concurrent.atomic.AtomicInteger;/*不保证原子性
* */
public class Demo29Volatile {//原子类的Integerprivate  static AtomicInteger num=new AtomicInteger();//volatile加上以后不能保证20000次执行结果,所以volatile不保证原子性!!public static  void add(){//synchronized加上以后可以保证20000次执行,//num++;//num++本身就不是一个原子性操作/* getAndIncrement +1方法    这个方法本质是使用了CAS,跟底层操作系统弄挂钩,所以效率比较高,在内存中修改值* 它是一个很特殊的存在*/num.getAndIncrement();}public static void main(String[] args) {//理论上的结果为20000for (int i = 1; i <= 20; i++) {new Thread(()->{for (int i1 = 1; i1 <= 1000; i1++) {add();}}).start();}while (Thread.activeCount()>2){//activeCount是还存活的线程的数量,除开main和gc以外才可以0Thread.yield();//礼让}System.out.println(Thread.currentThread().getName()+" "+num);}
}

23指令重排详解

/指令重排
什么是指令重排?————你写的程序,计算机并不是按照那样子去执行
源代码>编译器优化重排>指令并行可能也会重排>内存系统可能也会重排>执行
处理器在进行指令重排的时候,会考虑数据之间的依赖性
因为指令重排会导致结果错误,所以Volatile可以避免指令重排导致的错误结果
只要加了Volatile就会产生

内存屏障CPU指令,作用***:1.可以特定的操作的顺序2.可以保证某些变量的内存可见性
(利用这些特性Volatile实现了可见性)
内存屏障的作用:中间产生内存屏障,禁止上下的指令顺序交换
Volatile可以保持可见性、不能保证原子性,但是由于内存屏障,可以保证避免出现指令重排的现象产生
Volatile在单例模式在玩的最多
单例模式:

  • */

24单例模式(饿汉模式和懒汉模式)

package JUC;
/*懒汉式单例
* */
public class Demo32LazyMan {private Demo32LazyMan() {System.out.println(Thread.currentThread().getName()+"ok");}private volatile static Demo32LazyMan demo32LazyMan;//避免出现指令重拍错误结果,必须加Volatilepublic static Demo32LazyMan getInstance(){//加锁的操作,双重检测锁模式的懒汉式单例——DCL懒汉式if (demo32LazyMan == null) {synchronized (Demo32LazyMan.class){if (demo32LazyMan==null){demo32LazyMan=new Demo32LazyMan();      //不是一个原子性操作/*1.分配内存空间2. 执行构造方法,初始化对象3.把这个对象指向这个空间* */}}}return demo32LazyMan;}//单线程下单例ok,多线程下有问题,所以需要加锁public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(()->{demo32LazyMan.getInstance();}).start();}}}

25深入理解CAS

/*什么是CAS?
比较当前工作内存中的值,如果这个值是期望的,那么执行操作,如果不是那么就一直循环
CAS:compareAndSet:比较并交换
CAS:ABA问题:(狸猫换太子)
缺点:
1.循环会耗时
2.一次性只能保证一个共享变量的原子性
3.会产生ABA问题
Unasfe类可以让java操作内存,java正常是不可以操作内存的,C++可以,所以它相当于java的后门

  • */

26原子引用解决ABA问题(需要引入原子引用-27节提到)

两条线程同时操作的时候,第二条线程第一次把3修改成1,但是对于第一条线程来说,原来的她已经不再是原来的她,虽然看起来是一样(狸猫换太子)

26.1ABA问题

package ceshi;
import java.util.concurrent.atomic.AtomicReference;
public class Demo01 {//ABA问题public static void main(String [] args) throws InterruptedException {AtomicReference<String> ref=new AtomicReference<String>("A");String prev=ref.get();new Thread(()-> {System.out.println("change A->B "+ref.compareAndSet("A", "B"));//盲区,do sthSystem.out.println("change B->A "+ref.compareAndSet("B", "A"));}).start();Thread.sleep(1000);System.out.println("change A->C "+ref.compareAndSet(prev, "C"));}
}

26.2原子引用解决ABA问题

package ceshi;
import java.util.concurrent.atomic.AtomicStampedReference;
public class Demo02 {//解决ABA问题/*步骤:1.new AtomicStampedReference            (新建原子戳引用)2.ref.getReference();                   (获得参考)3.ref.getStamp()                        (获得印章)4.new Thread                            (创建线程,输出原子引用实例AB之间的转换)5.ref.compareAndSet(prev, "C",mstamp,1)  (输出盖章为目标转换到C的结果)* */public static void main(String [] args) throws InterruptedException {AtomicStampedReference<String> ref=new AtomicStampedReference<String>("A",0);String prev=ref.getReference();int mstamp=ref.getStamp();new Thread(()-> {int stamp=ref.getStamp();System.out.println("change A->B "+ref.compareAndSet("A", "B",stamp,1));//不再是盲区    do sth unknown.....stamp=ref.getStamp();System.out.println("change B->A "+ref.compareAndSet("B", "A",stamp,1));}).start();Thread.sleep(1000);System.out.println("change A->C "+ref.compareAndSet(prev, "C",mstamp,1));}}

27可重入锁

各种锁的理解:
1.公平锁与非公平锁
公平锁:公平,不可以插队
非公平锁:不公平,可以插队,默认都是非公平锁(因为比较公平)
2.可重入锁(递归锁):

28自旋锁

package JUC;import java.util.concurrent.atomic.AtomicReference;/*自旋锁
* */
public class Demo38SpinLock {AtomicReference<Thread> atomicReference=new AtomicReference<>();public void myLock(){Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName()+"myLock");while (!atomicReference.compareAndSet(null,thread)){}}public void myUnLock(){Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName()+"myUnLock");atomicReference.compareAndSet(thread,null);}
}

测试自旋锁

package JUC;import java.util.concurrent.TimeUnit;public class Demo39TestSpinLock {public static void main(String[] args) throws InterruptedException {Demo38SpinLock lock = new Demo38SpinLock();new Thread(()->{lock.myLock();try {TimeUnit.SECONDS.sleep(3);} catch (Exception e) {e.printStackTrace();} finally {lock.myUnLock();}},"T1").start();TimeUnit.SECONDS.sleep(3);new Thread(()->{lock.myLock();try {TimeUnit.SECONDS.sleep(1);} catch (Exception e) {e.printStackTrace();} finally {lock.myUnLock();}},"T2").start();}
}

29死锁排查(jps)

package JUC;import java.util.concurrent.TimeUnit;/*死锁的情况
两个对象互相都想拿对方的锁
解决办法:
使用jps定位进程号
* */
public class Demo40Lock {public static void main(String[] args) {String lockA="lockA";String lockB="lockB";new Thread(new MyThread(lockA,lockB),"T1").start();new Thread(new MyThread(lockB,lockA),"T2").start();}}
class MyThread implements Runnable{private String lockA;private String lockB;public MyThread(String lockA, String lockB) {this.lockA = lockA;this.lockB = lockB;}@Overridepublic void run() {synchronized (lockA){System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"=>get"+lockB);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockB){System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>get"+lockA);}}}
}

解决问题

1.使用jps -l定位进程号
运行之后Terminal输入jps -l就会查处具体的线程信息

2.使用jstack查看进程信息
输入jstack 14212
得到以下的结果

30乐观锁、悲观锁(无内容)

这个问题可以自行查询~

JUC详解(各种乱七八糟的锁)相关推荐

  1. JUC详解 | JUC Lock

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 JUC详解 | JUC Lock锁的详解 前言 一.Lock锁的入门 1. ReentrantLock可重入锁 1.1 测试可重入性 ...

  2. Java开发 - 不知道算不算详细的JUC详解

    前言 大概有快两周没有发文了,这段时间不断的充实自己,算算时间,也到了该收获的时候,今天带来一篇JUC详解,但说实话,我也不敢自信它详不详细.JUC说白了就是多线程,学Java不久的人知道多线程,恐怕 ...

  3. python 线程安全的数据类型_详解python多线程、锁、event事件机制的简单使用

    详解python多线程.锁.event事件机制的简单使用 发布时间:2020-09-25 02:04:12 来源:脚本之家 阅读:117 作者:君惜 线程和进程 1.线程共享创建它的进程的地址空间,进 ...

  4. redis watch使用场景_详解redis中的锁以及使用场景

    分布式锁 什么是分布式锁? 分布式锁是控制分布式系统之间同步访问共享资源的一种方式. 为什么要使用分布式锁? ​ 为了保证共享资源的数据一致性. 什么场景下使用分布式锁? ​ 数据重要且要保证一致性 ...

  5. Java - JUC详解

    目录 一.了解和JUC相关的概念 二.Java线程 三.线程共享模型 一.了解和JUC相关的概念 1.1 什么是JUC? JUC是java.util.concurrent包的简称,在Java5.0添加 ...

  6. Java锁详解:“独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁+线程锁”

    在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 线程锁 乐观锁 VS 悲 ...

  7. 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

    在Java并发场景中,会涉及到各种各样的锁,比如:高并发编程系列:4种常用Java线程锁的特点,性能比较.使用场景,这些锁有对应的种类:公平锁,乐观锁,悲观锁等等,这篇文章来详细介绍各种锁的分类: 公 ...

  8. Mysql 死锁过程及案例详解之清空缓存锁Flush Lock

    Mysql 清空缓存锁Flush Lock 清空缓存锁Flush Locks flush table的功能是关闭所有打开的表,强制关闭所有正在使用的表,并刷新准备好的语句缓存. 这种操作需要用户拥有  ...

  9. 【直击DTCC】浪潮霍俊路详解数据库集群锁机制管理

    2016年5月12日-14日,第七届中国数据库技术大会(DTCC 2016)在北京国际会议中心拉开帷幕.今年的大会首次设立了"数据库内核技术"专场,着重突出"内核的实现技 ...

最新文章

  1. 深度插值与透视纹理映射插值
  2. pyhon 数据类型转换函数
  3. Linux下使用Google Authenticator配置SSH登录动态验证码
  4. php 循环向select添加选项
  5. oracle 显示最后几条,oracle 先分组后获取每组最大值的该条全部信息
  6. OpenCV相机运动估计
  7. 深入体验JavaWeb开发内幕——简述JSP中的自定义标签叫你快速学会
  8. 结对作业2:单元测试
  9. 【今日CV 计算机视觉论文速览】 11 Mar 2019
  10. 亚信java在线测评题库_校招秋招,网申在线测评如何训练才能通过?
  11. 微信支付推出限量红包封面 两大途径赢取
  12. 在微信小程序中绘制图表(part3)
  13. 哪个服务器比较稳定,云服务器哪个比较稳定
  14. 【语音判别】基于matlab双门限法判别语音信号【含Matlab源码 1720期】
  15. JVM内存模型及CMS、G1和ZGC垃圾回收器详解
  16. j1900适合装哪版群晖_NAS部署指南 群晖篇六—— NAS兼做路由器,群晖虚拟机套件教程...
  17. 电脑蓝屏怎么办?一分钟教你修好
  18. 16秋南开计算机应用答案,南开16秋学期《计算机应用基础》在线作业.doc
  19. 【原创】PID控制算法模拟器
  20. IPv6接口自动配置的地址数量

热门文章

  1. 数据结构(Java实现)-详谈树与二叉树结构
  2. Flash AS3.0实战
  3. 传智教育|2022最新版Java学习路线图全集汇总——Java学习到底学什么?一文详解
  4. ctfshow web171-174
  5. 最新县及县以上行政区划代码(截止2012年10月31日)
  6. 最好用的:桌面搜索工具(或:硬盘搜索) 是什么?BBdoc文档搜索工具!
  7. tar无法解压bz2压缩包问题
  8. C# Sharp问题解决:System.FormatException 输入字符串的格式不正确
  9. 思科路由器ios系统学习
  10. 每日定时推送股票数据到表单搭建示例