多线程进阶=》JUC并发编程02
在JUC并发编程01中说到了,什么是JUC、线程和进程、Lock锁、生产者和消费者问题、8锁现象、集合类不安全、Callable(简单)、常用辅助类、读写锁
https://blog.csdn.net/qq_45441466/article/details/117197861
10、阻塞队列
阻塞队列:BlockingDeque
什么情况下我们会使用阻塞队列:
多线程并发处理,线程池!
学会使用队列
添加、移除
四组API
方式 | 抛出异常 | 由返回值 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer() | put() | offer(“d”, 2,TimeUnit.SECONDS) |
移除 | remove | poll() | take() | poll(2,TimeUnit.SECONDS) |
判断队列首 | element | peek() |
package com.panghl.juc.bq;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;/*** @Author panghl* @Date 2021/6/1 19:28* @Description BlockQueue**/
public class Test {public static void main(String[] args) throws InterruptedException {// test1();
// test2();
// test3();test4();}/*** 抛出异常*/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"));//IllegalStateException: Queue full 抛出异常!//System.out.println(blockingQueue.add("d"));System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());//java.util.NoSuchElementException 抛出异常
// System.out.println(blockingQueue.remove());System.out.println(blockingQueue.peek());//检测队首元素System.out.println(blockingQueue.element());//查看队首元素是谁}/*** 有返回值*/public static void test2(){BlockingQueue 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.element());//查看队首元素是谁System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.peek());//检测队首元素System.out.println(blockingQueue.element());//查看队首元素是谁}/*** 等待,阻塞(一直阻塞)*/public static void test3() throws InterruptedException {BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);//一直阻塞blockingQueue.put("a");blockingQueue.put("b");blockingQueue.put("c");blockingQueue.put("d"); //队列没有位置了,一直阻塞System.out.println(blockingQueue.take());System.out.println(blockingQueue.take());System.out.println(blockingQueue.take());System.out.println(blockingQueue.take()); //没有这个元素,一直阻塞}/*** 超时等待*/public static void test4() throws InterruptedException {BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);//一直阻塞blockingQueue.offer("a");blockingQueue.offer("b");blockingQueue.offer("c");
// blockingQueue.offer("d", 2,TimeUnit.SECONDS); //2s 后无位置,超时退出blockingQueue.poll();blockingQueue.poll();blockingQueue.poll();blockingQueue.poll(2,TimeUnit.SECONDS);//等待超过2s就退出}
}
同步队列
没有容量,进去一个元素,必须等待取出来之后,才能往里面放一个元素!
put、take
package com.panghl.juc.bq;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;/*** @Author panghl* @Date 2021/6/1 20:21* @Description 同步队列* 和其他的BlockingQueue 不一样,SynchronousQueue 不存储元素* put了一个元素,必须从里面先take取出来,否则不能再put进去值!**/
public class SyncQueueDemo {public static void main(String[] args) {//同步队列BlockingQueue<String> syncQueue = new SynchronousQueue<>();new Thread(() -> {try {System.out.println(Thread.currentThread().getName() + "put 1");syncQueue.put("1");System.out.println(Thread.currentThread().getName() + "put 2");syncQueue.put("2");System.out.println(Thread.currentThread().getName() + "put 3");syncQueue.put("3");} catch (InterruptedException e) {e.printStackTrace();}}, "T1").start();new Thread(() -> {try {TimeUnit.SECONDS.sleep(2);System.out.println(Thread.currentThread().getName() + "take 1");syncQueue.take();TimeUnit.SECONDS.sleep(2);System.out.println(Thread.currentThread().getName() + "take 2");syncQueue.take();TimeUnit.SECONDS.sleep(2);System.out.println(Thread.currentThread().getName() + "take 3");syncQueue.take();} catch (InterruptedException e) {e.printStackTrace();}}, "T2").start();}
}
11、线程池(重点)
池化技术:程序的运行,本质:占用系统的资源!优化资源的使用!事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。
线程池的好处
1、降低资源的消耗
2、提高响应的速度
3、方便管理
线程复用,可以控制最大并发数、管理线程
线程池:三大方法
package com.panghl.juc.pool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @Author panghl* @Date 2021/6/1 20:37* @Description 工具类 :3大方法* 使用了线程池之后,使用线程池来创建线程**/
public class Demo01 {public static void main(String[] args) {// ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
// ExecutorService threadPool = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小ExecutorService threadPool = Executors.newCachedThreadPool(); //可伸缩的,遇强则强,遇弱则弱try {for (int i = 0; i < 10; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "ok");});}} catch (Exception e) {e.printStackTrace();} finally {//线程池用完,程序结束,关闭线程池threadPool.shutdown();}}
}
7大参数
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}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>());}//本质:ThreadPoolExecutor()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;}
手动创建一个线程池
四种拒绝策略
package com.panghl.juc.pool;import java.util.concurrent.*;/*** @Author panghl* @Date 2021/6/1 20:37* @Description 工具类 :4种拒绝策略
new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人进来,不处理这个人的,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里! main线程执行
new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!**/
public class Demo02 {public static void main(String[] args) {// 自定义线程池!工作 ThreadPoolExecutorExecutorService threadPool = new ThreadPoolExecutor(2,5,3,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!);try {//最大承载:Deque + max//超过 RejectedExecutionExceptionfor (int i = 1; i <=9; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "ok");});}} catch (Exception e) {e.printStackTrace();} finally {//线程池用完,程序结束,关闭线程池threadPool.shutdown();}}
}
new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人进来,不处理这个人的,抛出异常 new
ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里! main线程执行 new
ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常! new
ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!
小结和扩展
最大线程到底该如何定义?
1、CPU 密集型 ; 几核,就是几,可以保持CPU的效率最高!
2、IO 密集型 ; 判断你程序中十分耗IO的线程。
程序 15个大型任务 io十分占用资源!
package com.panghl.juc.pool;import java.util.concurrent.*;/*** @Author panghl* @Date 2021/6/1 20:37* @Description 工具类 :4种拒绝策略
new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人进来,不处理这个人的,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里! main线程执行
new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!**/
public class Demo02 {public static void main(String[] args) {// 自定义线程池!工作 ThreadPoolExecutor//最大线程到底该如何定义?//1、CPU 密集型 ; 几核,就是几,可以保持CPU的效率最高!//2、IO 密集型 ; 判断你程序中十分耗IO的线程。// 程序 15个大型任务 io十分占用资源!//获取CPU的核数System.out.println(Runtime.getRuntime().availableProcessors());ExecutorService threadPool = new ThreadPoolExecutor(2,Runtime.getRuntime().availableProcessors(),3,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!);try {//最大承载:Deque + max//超过 RejectedExecutionExceptionfor (int i = 1; i <=9; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "ok");});}} catch (Exception e) {e.printStackTrace();} finally {//线程池用完,程序结束,关闭线程池threadPool.shutdown();}}
}
12、四大函数式接口(必须掌握)
@FunctionalInterface
public interface Runnable {public abstract void run();
}
//超级多FunctionalInterface
//简化编程模型,在新版本的框架底层大量应用!
//foreach (消费者类的函数式接口)
代码测试:
Function函数式接口
package com.panghl.juc.function;import java.util.function.Function;/*** @Author panghl* @Date 2021/6/1 21:32* @Description Function 函数式接口,有一个输入参数,有一个输出* 只要是函数式接口可以用lambda表达式简化**/
public class Demo01 {public static void main(String[] args) {//工具类:输出输入的值
// Function<String, String> function = new Function<String, String>() {// @Override
// public String apply(String o) {// return o;
// }
// };Function<String, String> function = (str)->{return str;};System.out.println(function.apply("1"));}
}
断定型接口
package com.panghl.juc.function;import java.util.function.Predicate;/*** @Author panghl* @Date 2021/6/1 21:40* @Description 断定性接口:有一个输入参数,返回值只能是 布尔值!**/
public class Demo2 {public static void main(String[] args) {//判断字符串是否为null
// Predicate<String> predicate = new Predicate<String>() {// @Override
// public boolean test(String o) {// return o.isEmpty();
// }
// };Predicate<String> predicate = (str)->{return str.isEmpty();};System.out.println(predicate.test("1"));}
}
Consumer 消费型接口
package com.panghl.juc.function;import java.util.function.Consumer;/*** @Author panghl* @Date 2021/6/1 21:48* @Description Consumer 消费型接口:只有输入,没有返回值**/
public class Demo03 {public static void main(String[] args) {// Consumer<String> consumer = new Consumer<String>() {// @Override
// public void accept(String str) {// System.out.println(str);
// }
// };Consumer<String> consumer = (str) -> {System.out.println(str);};consumer.accept("helo");}
}
Supplier 供给型接口
package com.panghl.juc.function;import java.util.function.Supplier;/*** @Author panghl* @Date 2021/6/1 21:50* @Description Supplier 供给型接口,没有参数,只有返回值**/
public class Demo04 {public static void main(String[] args) {// Supplier<String> supplier = new Supplier<String>() {// @Override
// public String get() {// return "helo";
// }
// };Supplier<String> supplier = ()->{return "adhelo";};System.out.println(supplier.get());}
}
13、Stream流式计算
package com.panghl.juc.stream;import java.util.Arrays;
import java.util.List;/*** @Author panghl* @Date 2021/6/1 21:58* @Description 题目要求:一分钟内完成此题,只能用一行代码实现!* 1、ID必须是偶数* 2、年龄必须大于23岁* 3、用户名转为大写字母* 4、用户名字母倒着排序* 5、只输出一个用户!**/
public class Test {public static void main(String[] args) {User u1 = new User(1, "a", 21);User u2 = new User(2, "b", 22);User u3 = new User(3, "c", 23);User u4 = new User(4, "d", 24);User u5 = new User(5, "e", 25);List<User> users = Arrays.asList(u1, u2, u3, u4, u5);users.stream().filter((u) -> {return u.getId() % 2 == 0;}).filter((u)->{return u.getAge()>23;}).map((u)->{return u.getName().toUpperCase();}).sorted((o1,o2)->{return o1.compareTo(o2);}).limit(1).forEach(System.out::println);}
}
14、ForkJoin
什么是ForkJoin
ForkJoin在JDK1.7,并执行任务!提高效率。大数据量!
大数据:Map Reduce(把大任务拆分为小任务)
ForkJoin特点:工作窃取
这个里面维护的都是双端队列
ForkJoin
package com.panghl.juc.forkjoin;import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;/*** @Author panghl* @Date 2021/6/2 22:30* @Description 求和计算的任务!* 3000 6000(ForkJoin) 9000(Stream并行流)* 如何使用forkjoin ?* 1、forkjoinPool 通过它来执行* 2、计算任务 forkjoinPool.execute(ForkJoinTask task)* 3、要继承ForkJoinTask**/
public class ForkJoinDemo extends RecursiveTask<Long> {private Long start; //1private Long end; //1990900000//临界值private Long temp = 10000L;public ForkJoinDemo(Long start, Long end) {this.start = start;this.end = end;}@Overrideprotected Long compute() {if ((end - start) > temp) {//分支合并计算Long sum = 0L;for (Long i = start; i < end; i++) {sum += i;}System.out.println(sum);return sum;} else { //forkjoinlong middle = (start + end) / 2; //中间值ForkJoinDemo forkJoinDemo1 = new ForkJoinDemo(start, middle);forkJoinDemo1.fork(); //拆分任务,把任务压入线程队列ForkJoinDemo forkJoinDemo2 = new ForkJoinDemo(middle + 1, end);forkJoinDemo2.fork();return forkJoinDemo1.join() + forkJoinDemo2.join();}}}
package com.panghl.juc.forkjoin;import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;/*** @Author panghl* @Date 2021/6/2 22:45* @Description TODO**/
public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {test3();}public static void test1(){Long sum = 0L;long start = System.currentTimeMillis();for (Long i = 1L; i < 10_0000_000; i++) {sum+=i;}long end = System.currentTimeMillis();System.out.println("sum="+"时间:"+(end-start));}//会使用ForkJoinpublic static void test2() throws ExecutionException, InterruptedException {long start = System.currentTimeMillis();ForkJoinPool forkJoinPool = new ForkJoinPool();ForkJoinDemo forkJoinDemo = new ForkJoinDemo(0L,10_0000_000L);ForkJoinTask<Long> forkJoinTask = forkJoinPool.submit(forkJoinDemo);Long aLong = forkJoinTask.get();long end = System.currentTimeMillis();System.out.println("sum="+aLong+"时间:"+(end-start));}//Stream并行流public static void test3(){long start = System.currentTimeMillis();long reduce = LongStream.rangeClosed(0L, 10_0000_000L).parallel().reduce(0, Long::sum);long end = System.currentTimeMillis();System.out.println("sum="+reduce+"时间:"+(end-start));}
}
15、异步回调
package com.panghl.juc.future;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;/*** @Author panghl* @Date 2021/6/2 23:02* @Description 异步调用: Ajax* 异步执行 成功回调**/
public class Demo01 {public static void main(String[] args) throws ExecutionException, InterruptedException {//发送一个请求--》没有返回值的runAsync 异步回调
// CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{// try {// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName()+"休眠结束===>runSync=>Void");
// });
// System.out.println("1111");
// completableFuture.get(); //获取阻塞执行结果//有返回值的 supplyAsync 异步回调//ajax,成功和失败的回调//返回的是错误信息;CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{int i = 1/0;System.out.println(Thread.currentThread().getName()+"休眠结束===>runSync=>Integer");return 1024;});completableFuture.whenComplete((t,u)->{System.out.println("t=>"+t); //正常的返回结果System.out.println("u=>"+u); //错误信息:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero}).exceptionally((e)->{System.out.println(e.getMessage());return 233; //可以获取到错误的返回结果});Integer integer = completableFuture.get();System.out.println(integer);}
}
16、JMM
Volatile是Java虚拟机提供轻量级的同步机制
1、保证可见性
2、不保证原子性
3、禁止指令重排
什么是JMM?
JMM:Java内存模型,不存在的东西,概念!约定!
关于JMM的一些同步的约定:
1、线程解锁前,必须把共享变量立刻刷回主存。
2、线程加锁前,必须读取主存中的最新值到工作内存中!
3、加锁和解锁是同一把锁
线程 工作内存、主内存
8中操作:
问题:程序不知道主内存的值被修改了。
package com.panghl.juc.volatil;import java.util.concurrent.TimeUnit;/*** @Author panghl* @Date 2021/6/2 23:36* @Description**/
public class JMMDemo {private static int num = 0;public static void main(String[] args) throws InterruptedException {new Thread(() -> {//线程1while (num == 0) {}}).start();TimeUnit.SECONDS.sleep(2);num = 1;System.out.println(num);}}
18.Volatile
1、保证了可见性
package com.panghl.juc.volatil;import java.util.concurrent.TimeUnit;/*** @Author panghl* @Date 2021/6/2 23:36* @Description**/
public class JMMDemo {private static volatile int num = 0;public static void main(String[] args) throws InterruptedException {new Thread(() -> {//线程1while (num == 0) {}}).start();TimeUnit.SECONDS.sleep(2);num = 1;System.out.println(num);}}
2、不保证原子性
原子性:不可分割
线程A在执行任务的时候,不能被打扰,也不能被分割。要么同时成功,要嘛同时失败。
package com.panghl.juc.volatil;/*** @Author panghl* @Date 2021/6/2 23:44* @Description 不保证原子性**/
public class VDemo02 {private volatile static int num = 0;private static void add(){num++;}public static void main(String[] args) {for (int i = 0; i < 20; i++) {new Thread(()->{for (int i1 = 0; i1 < 1000; i1++) {add();}}).start();}while (Thread.activeCount()>2){//main gc 默认执行Thread.yield();}System.out.println(Thread.currentThread().getName()+"==>num:"+num);}
}
如果不加lock和synchronized,怎么样保证原子性?
使用原子类,解决原子性问题
package com.panghl.juc.volatil;import java.util.concurrent.atomic.AtomicInteger;/*** @Author panghl* @Date 2021/6/2 23:44* @Description 不保证原子性**/
public class VDemo02 {//原子类的 Integerprivate volatile static AtomicInteger num = new AtomicInteger();private static void add(){// num++; //你是一个原子性操作num.getAndIncrement(); //AtomicInteger+1 的方法, CAS}public static void main(String[] args) {for (int i = 0; i < 20; i++) {new Thread(()->{for (int i1 = 0; i1 < 1000; i1++) {add();}}).start();}while (Thread.activeCount()>2){//main gc 默认执行Thread.yield();}System.out.println(Thread.currentThread().getName()+"==>num:"+num);}
}
这些类的底层都直接和操作系统挂钩!在内存中修改值!Unsafe类是一个很特殊的存在!
3、指令重排
什么是指令重排:你写的程序,计算机并不是按照你写的那样去执行的。
源代码–》编译器优化的重排–》指令并行也可能会重排–》内存系统也会重排–》执行
处理器在进行指令重排的时候,考虑:数据之间的依赖性!
int x =1; //1
int y = 2; //2
x=x+5; //3
y=x*x; //4
我们所期望的:1234 结果2134 1324
可能造成影响的结果: ab xy 这四个值默认都是0;
线程A | 线程B |
---|---|
x=a | y=b |
b=1 | a=2 |
正常的结果:x=0;y=0 ;但是可能由于指令重排
线程A | 线程B |
---|---|
b=1 | a=2 |
x=a | y=b |
指令重排导致的诡异结果:x=2;y=1;
volatile 可以避免指令重排
内存屏障。CPU指令。作用:
1、保证特定的操作的执行顺序!
2、可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)
volatile是可以保证可见性。不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生!
20、深入理解CAS
什么是CAS
大厂必须要深入研究底层!有所突破!修内功,操作系统,计算机网络原理
Unsafe类
CAS: 比较当前工作内存中的值和主内存的值,如果这个值是期望的,那么执行操作!如果不是就一直循环。
缺点:
1、循环会耗时
2、一次性只能保证一个共享变量的原子性
3、ABA问题
CAS:ABA问题(狸猫换太子)
package com.panghl.juc.cas;import java.util.concurrent.atomic.AtomicInteger;/*** @Author panghl* @Date 2021/6/3 21:33* @Description TODO**/
public class CASDemo {//CAS compareAndSet: 比较并交换!public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(2020);// 期望、更新// public final boolean compareAndSet(int expect, int update)//如果我期望的值达到了,name就更新,否则,就不更新,CAS 是CPU的并发原语atomicInteger.compareAndSet(2020,2021);System.out.println(atomicInteger.get());// ===============捣乱的线程============System.out.println(atomicInteger.compareAndSet(2020,2021));System.out.println(atomicInteger.get());System.out.println(atomicInteger.compareAndSet(2021,2020));System.out.println(atomicInteger.get());// ===============期望的线程============System.out.println(atomicInteger.compareAndSet(2020,6666));System.out.println(atomicInteger.get());}
}
21、原子引用
解决ABA问题,引入原子引用!对应的思想:乐观锁
带版本号的原子操作。
注意
package com.panghl.juc.cas;import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;/*** @Author panghl* @Date 2021/6/3 21:33* @Description TODO**/
public class CASDemo {//CAS compareAndSet: 比较并交换!public static void main(String[] args) {// AtomicInteger atomicInteger = new AtomicInteger(2020);//int Integer 注意,如果泛型是一个包装类,注意对象的引用问题!!!//正常在业务操作,这里面比较的都是一个个对象AtomicStampedReference<Integer> atomicReference = new AtomicStampedReference<>(1,1);// 乐观锁的原理相同!!!new Thread(()->{int stamp = atomicReference.getStamp(); //获取版本号System.out.println("A1->"+stamp);try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(atomicReference.compareAndSet(1, 2, atomicReference.getStamp(), atomicReference.getStamp() + 1));System.out.println("A2->"+atomicReference.getStamp());System.out.println(atomicReference.compareAndSet(2, 1, atomicReference.getStamp(), atomicReference.getStamp() + 1));System.out.println("A2->"+atomicReference.getStamp());},"A").start();new Thread(()->{int stamp = atomicReference.getStamp(); //获取版本号System.out.println("B1->"+stamp);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(atomicReference.compareAndSet(1, 3, stamp, stamp + 1));System.out.println("B2->"+atomicReference.getStamp());},"B").start();}
}
21、各种锁的理解
1、公平锁、非公平锁
公平锁:非常公平,不能够插队,必须先来后到!
非公平锁:非常不公平,可以插队(默认非公平锁)
2、可重入锁
可重入锁(递归锁)
Synchronized版本
package com.panghl.juc.lock;/*** @Author panghl* @Date 2021/6/3 22:16* @Description Synchronized**/
public class Demo01 {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()+"sms");call(); //这里也有锁}public synchronized void call(){System.out.println("打电话");}
}
Lock版本
package com.panghl.juc.lock;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @Author panghl* @Date 2021/6/3 22:19* @Description Lock**/
public class Demo02 {public static void main(String[] args) {Phone2 phone = new Phone2();new Thread(() -> {phone.sms();}, "A").start();new Thread(() -> {phone.sms();}, "B").start();}
}class Phone2 {Lock lock = new ReentrantLock();public void sms() {lock.lock();// lock 锁必须配对,否则就会死在里面lock.lock();try {System.out.println(Thread.currentThread().getName() + "sms");call(); //这里也有锁} catch (Exception e) {e.getMessage();} finally {lock.unlock();lock.unlock();}}public void call() {lock.lock();try {System.out.println(Thread.currentThread().getName() +"打电话");} catch (Exception e) {e.getMessage();} finally {lock.unlock();}}
}
3、自旋锁
自定义锁测试:
package com.panghl.juc.lock;import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;/*** @Author panghl* @Date 2021/6/3 22:26* @Description 自旋锁**/
public class SpinlockDemo {// int 0// Thread nullAtomicReference<Thread> atomicReference = new AtomicReference<>();//加锁public void myLock(){Thread thread = Thread.currentThread();System.out.println(thread.getName()+"==>lock");// 自旋锁while (!atomicReference.compareAndSet(null,thread)){System.out.println("自旋中....");}}//解锁public void myUnLock(){Thread thread = Thread.currentThread();System.out.println(thread.getName()+"==>myUnlock");atomicReference.compareAndSet(thread,null);}}
package com.panghl.juc.lock;import java.util.concurrent.TimeUnit;/*** @Author panghl* @Date 2021/6/3 22:30* @Description**/
public class TestSpinLock {public static void main(String[] args) {//底层使用的自旋锁CASSpinlockDemo spinlockDemo = new SpinlockDemo();new Thread(()->{spinlockDemo.myLock();try {TimeUnit.SECONDS.sleep(3);}catch (Exception e){e.getMessage();}finally {spinlockDemo.myUnLock();}},"A1").start();new Thread(()->{spinlockDemo.myLock();try {TimeUnit.SECONDS.sleep(1);}catch (Exception e){e.getMessage();}finally {spinlockDemo.myUnLock();}},"A2").start();}
}
4、死锁
死锁测试,怎么排除死锁:
package com.panghl.juc.lock;import java.util.concurrent.TimeUnit;/*** @Author panghl* @Date 2021/6/3 22:37* @Description 死锁**/
public class DeadLockDemo {public static void main(String[] args) {String lockA="lockA";String lockB="lockB";new Thread(new MyThread(lockA,lockB),"A1").start();new Thread(new MyThread(lockB,lockA),"A2").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 定位进程号
2、使用 jstack 进程号 找到死锁问题
多线程进阶=》JUC并发编程02相关推荐
- JUC并发编程02——AQS源码剖析
1.AQS介绍 相信每个Java Coder 都使用过或者至少听说过AQS, 它是抽象队列同步器AbstractQueuedSynchronizer 的简称,在juc包下.它提供了一套可用于实现锁同步 ...
- 【尚硅谷】大厂必备技术之JUC并发编程——笔记总结
[JUC并发编程01]JUC概述 关键字:进程和线程.进程和线程.wait和sleep.并发与并行.管程.用户线程和守护线程 [JUC并发编程02]Lock接口 关键字:synchronized.Lo ...
- 多线程进阶=》JUC并发编程
多线程进阶=>JUC并发编程 1.什么是JUC JUC是java.util.concurrent的简写. 用中文概括一下,JUC的意思就是java并发编程工具包. 并发编程的本质就是 ...
- 基于《狂神说Java》JUC并发编程--学习笔记
前言: 本笔记仅做学习与复习使用,不存在刻意抄袭. -------------------------------------------------------------------------- ...
- JUC并发编程(java util concurrent)(哔站 狂神说java juc并发编程 摘录笔记)
JUC并发编程(java util concurrent) 1.什么是JUC JUC并不是一个很神秘的东西(就是 java.util 工具包.包.分类) 业务:普通的线程代码 Thread Runna ...
- 爬梯:JUC并发编程(三)
学习资源整理自:B站<狂神说> 书接上回 JUC并发编程 12.CompletableFuture 异步回调 理解 父类:Future,对将来的某个事件的结果进行建模 可以用ajax进行理 ...
- ❤️《JUC并发编程从入门到高级》(建议收藏)❤️
JUC并发编程 1.什么是JUC JUC的意思就是java并发编程工具包,与JUC相关的有三个包:java.util.concurrent.java.util.concurrent.atomic.ja ...
- Java JUC并发编程详解
Java JUC并发编程详解 1. JUC概述 1.1 JUC简介 1.2 进程与线程 1.2 并发与并行 1.3 用户线程和守护线程 2. Lock接口 2.1 Synchronized 2.2 什 ...
- JUC并发编程小总结
JUC是Java编发编程中使用的工具类,全称为java.util.concurrent.近期在大厂面试中屡屡被问到关于JUC的相关知识点问题,其重要性不言而喻,学好用好JUC可以说是每一个Java程序 ...
最新文章
- 区块链教程Fabric1.0源代码分析Peer peer channel命令及子命令实现
- 互联网公司IT系统架构进化之路
- AD在Windows Server 2003中的更新(中)
- 第八节:详细讲解Java中的异常处理情况与I/O流的介绍以及类集合框架
- 困了。还得背课文。变词型
- java 桥接模式_JAVA设计模式之【桥接模式】
- 用java进行LDAP用户登陆(用户认证)及修改密码
- VMware 修复 Workstation、Fusion 中多个严重的代码执行漏洞
- python三本经典书籍-《python编程入门经典》python之父推荐这三本书让你更快入门...
- notification 是同步的
- 关于添加文件删除权限
- 城市数字孪生解决方案
- 构建AD域 、 管理AD域
- ssh命令行使用明文密码连接远程服务器并执行命令
- 无心剑中译莎士比亚诗20首
- tab按钮样式 vue_vant 解决tab切换插件标题样式自定义的问题
- 9. Go复合类型-数组
- 数据库操作的异常Cannot perform this operation because the connection pool has been close
- STM32F103C8T6基础开发教程(HAL库)—开发环境配置
- Circum Triangle(圆上三角形)
热门文章
- 机器学习中参数模型和非参数模型理解
- 表情识别(二)--基于CNN分类
- Socket TCP协议解决粘包、半包问题的三种解决方案
- 温习Android基础知识——《第一行代码(第三版)》读书笔记 Chapter 2 Kotlin语法
- 嵌入式系统导论(彭蔓蔓等·人民邮电出版社)课后习题答案
- Arcgis使用教程(十一)ARCGIS地图制图之经纬网格设置参数详解
- 计算机音乐谱巴啦啦小魔,天谕手游巴啦啦小魔仙乐谱代码分享
- 基带信号matlab仿真,基带信号仿真方法上篇
- 简单易懂应如何快速掌握超长激光测距仪相关性能指标TFNLR20KI激光测距仪带你走进其简单的世界
- Symantec Backup Exec 2010 安装报 bad ELF interpreter: No such file or directory