首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,389 阅读
2
Spring Cloud OAuth2.0
935 阅读
3
类的加载
920 阅读
4
SpringBoot自动装配原理
824 阅读
5
集合不安全问题
691 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Canvas
React
Linux
容器
Docker
Containerd
Podman
Kubernetes
Python
FastApi
OpenCV
数据分析
牛牛生活
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
React
Redis
OpenCV
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Canvas
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
蘇阿細
累计撰写
472
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Canvas
React
Linux
容器
Docker
Containerd
Podman
Kubernetes
Python
FastApi
OpenCV
数据分析
牛牛生活
页面
统计
关于
搜索到
21
篇与
的结果
2021-02-16
Stream流式计算
Stream流式计算将计算交给流来操作package com.sw.stream; import java.util.Arrays; import java.util.List; /** * @Author suaxi * @Date 2021/2/16 10:33 * 有5个用户,进行筛选 * 1、ID为偶数 * 2、年龄大于23岁 * 3、用户名转换为大写 * 4、用户名倒序排列 * 5、只输出一个用户 */ public class StreamTest { public static void main(String[] args) { User user1 = new User(1, "a", 20); User user2 = new User(2, "b", 21); User user3 = new User(3, "c", 22); User user4 = new User(4, "d", 23); User user5 = new User(6, "e", 24); //转换为List集合 List<User> list = Arrays.asList(user1, user2, user3, user4, user5); list.stream() .filter(u ->{return u.getId()%2==0;}) .filter(u ->{return u.getAge()>23;}) .map(u ->{return u.getName().toUpperCase();}) .sorted((u1,u2) ->{return u2.compareTo(u1);}) .limit(1) .forEach(System.out::println); } }
2021年02月16日
283 阅读
0 评论
0 点赞
2021-02-15
四大函数式接口
四大函数式接口函数式接口只有一个方法的接口4大函数式接口:consumer,funtion,predicate,supplierFunction函数式接口package com.sw.function; import java.util.function.Function; /** * @Author suaxi * @Date 2021/2/15 22:00 * Function函数式接口 */ public class Test01 { public static void main(String[] args) { // Function<String, String> function = new Function<String, String>() { // @Override // public String apply(String s) { // return s; // } // }; //lambda表达式简化 Function<String, String> function = (s) ->{ return s; }; System.out.println(function.apply("函数式接口测试")); } } Predicate断定型接口package com.sw.function; import java.util.function.Predicate; /** * @Author suaxi * @Date 2021/2/15 22:09 * Predicate断定型接口,返回值为boolean类型 */ public class PredicateTest { public static void main(String[] args) { // Predicate<String> predicate = new Predicate<String>() { // @Override // public boolean test(String s) { // return s.isEmpty(); // } // }; Predicate<String> predicate = (str) ->{ return str.isEmpty(); }; System.out.println(predicate.test("abc")); } } Consummer消费型接口package com.sw.function; import java.util.function.Consumer; /** * @Author suaxi * @Date 2021/2/15 22:17 * Consummer消费型接口,只有输入参数,没有返回值 */ public class ConsumerTest { public static void main(String[] args) { // Consumer<String> consumer = new Consumer<String>() { // @Override // public void accept(String s) { // System.out.println(s); // } // }; Consumer<String> consumer = (str) ->{ System.out.println(str); return; }; consumer.accept("消费型接口测试"); } } Supplier供给型接口package com.sw.function; import java.util.function.Supplier; /** * @Author suaxi * @Date 2021/2/15 22:25 * Supplier 供给型接口 没有输入参数,只有返回值 */ public class SupplierTest { public static void main(String[] args) { // Supplier<String> supplier = new Supplier<String>() { // @Override // public String get() { // return "你好,谢谢"; // } // }; Supplier<String> supplier = () -> { return "你好,谢谢"; }; System.out.println(supplier.get()); } }
2021年02月15日
86 阅读
0 评论
0 点赞
2021-02-14
线程池
线程池线程池:三大方法、7大参数、4种拒绝策略池化技术事先准备好一些资源,要用的时候从池子中取,用完之后还回去优点:降低资源的消耗提高响应速度方便管理三大方法package com.sw.pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @Author suaxi * @Date 2021/2/14 21:23 */ public class PoolTest { public static void main(String[] args) { //ExecutorService pool = Executors.newSingleThreadExecutor(); //单个线程 //ExecutorService pool = Executors.newFixedThreadPool(10); //创建一个固定大小的线程池 ExecutorService pool = Executors.newCachedThreadPool(); //线程池大小可弹性伸缩 try { for (int i = 0; i < 50; i++) { pool.execute(() -> { System.out.println(Thread.currentThread().getName() + "--->Pool Test"); }); } } catch (Exception e) { e.printStackTrace(); } finally { //线程池用完,程序结束,关闭线程池 pool.shutdown(); } } } 七大参数 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; }图片来源:狂神说Java手动创建一个线程池package com.sw.pool; import java.util.concurrent.*; /** * @Author suaxi * @Date 2021/2/14 21:23 * 4种拒绝策略: * AbortPolicy() 线程池满了,还有人进来,不处理这个人的请求,同时抛出异常 * CallerRunsPolicy() 哪里来的请求,回到哪里去(请求对应的主方法) * DiscardPolicy() 队列满了,丢掉后来的请求,不抛出异常 * DiscardOldestPolicy() 队列满了,尝试去和最早进行服务的窗口竞争,看那里的服务是否快要结束了,结束就进去提出请求,这种策略也不抛出异常 */ public class ThreadPoolExecutorTest { public static void main(String[] args) { //自定义线程池 ExecutorService pool = new ThreadPoolExecutor( 2, 5, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy()); try { for (int i = 0; i < 50; i++) { pool.execute(() -> { System.out.println(Thread.currentThread().getName() + "--->Pool Test"); }); } } catch (Exception e) { e.printStackTrace(); } finally { //线程池用完,程序结束,关闭线程池 pool.shutdown(); } } } 4种拒绝策略AbortPolicy() 线程池满了,还有人进来,不处理这个人的请求,同时抛出异常CallerRunsPolicy() 哪里来的请求,回到哪里去(请求对应的主方法)DiscardPolicy() 队列满了,丢掉后来的请求,不抛出异常DiscardOldestPolicy() 队列满了,尝试去和最早进行服务的窗口竞争,看那里的服务是否快要结束了,结束就进去提出请求,这种策略也不抛出异常小结1、线程池不允许使用Executor创建(不安全),而是通过ThreadPoolExecutor这样的方式2、如何定义线程池最大的大小?(1) CPU密集型根据cpu核数来设定Runtime.getRuntime().availableProcessors();(2) IO密集型判断程序中十分耗IO的线程,一般设置为其两倍的大小
2021年02月14日
97 阅读
0 评论
0 点赞
2021-02-14
阻塞队列
阻塞队列写:如果队列满了,就必须阻塞等待取:如果队列是空的,必须阻塞等待生产阻塞队列的四组API 抛出异常不抛异常,有返回值等待阻塞等待超时添加addofferputoffer(,,)移除removepolltakepoll(,)检测队首元素elementpeek--测试Demo:package com.sw.blockingQueue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/2/14 19:57 * 阻塞队列 */ public class BlockingQueueTest { public static void main(String[] args) throws InterruptedException { test04(); } //1.抛出异常 public static void test01(){ //队列初始大小为3 ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3); System.out.println(blockingQueue.add("A")); System.out.println(blockingQueue.add("B")); System.out.println(blockingQueue.add("C")); //java.lang.IllegalStateException: Queue full 队列已满 //System.out.println(blockingQueue.add("D")); System.out.println(blockingQueue.element()); //检测队首元素 System.out.println("-----分割线-----"); System.out.println(blockingQueue.remove()); System.out.println(blockingQueue.remove()); System.out.println(blockingQueue.remove()); //java.util.NoSuchElementException 没有目标元素 System.out.println(blockingQueue.remove()); } //2.不抛出异常,有返回值 public static void test02(){ //队列初始大小为3 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("-----分割线-----"); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); //null } //3.等待,阻塞(一直阻塞) public static void test03() throws InterruptedException { //队列初始大小为3 ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3); blockingQueue.put("A"); blockingQueue.put("B"); blockingQueue.put("C"); //blockingQueue.put("D"); //位置不够了,会一直阻塞 System.out.println("-----分割线-----"); System.out.println(blockingQueue.take()); System.out.println(blockingQueue.take()); System.out.println(blockingQueue.take()); System.out.println(blockingQueue.take()); //没有这个元素,会一直阻塞 } //4.等待,阻塞(等待超时) public static void test04() throws InterruptedException { //队列初始大小为3 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",2, TimeUnit.SECONDS)); //等待超过2秒退出 System.out.println(blockingQueue.peek()); System.out.println("-----分割线-----"); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS)); //等待超过2秒退出 } } SynchronousQueue 同步队列没有容量,put一个元素之后,必须先take取出来,才能再put进去值package com.sw.blockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/2/14 20:58 * 同步队列 */ public class SynchronousQueueTest { public static void main(String[] args) { //没有初始容量,put之后必须进行take,才能再进行put操作 BlockingQueue<String> synchronousQueue = new SynchronousQueue<>(); //put new Thread(() -> { try { System.out.println(Thread.currentThread().getName() + "进行put01操作"); synchronousQueue.put("Hello"); System.out.println(Thread.currentThread().getName() + "进行put02操作"); synchronousQueue.put("nihao"); System.out.println(Thread.currentThread().getName() + "进行put03操作"); synchronousQueue.put("xiexie"); } catch (InterruptedException e) { e.printStackTrace(); } }, "A").start(); //take new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "--->" + synchronousQueue.take()); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "--->" + synchronousQueue.take()); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "--->" + synchronousQueue.take()); } catch (InterruptedException e) { e.printStackTrace(); } }, "B").start(); /* 输出结果: A进行put01操作 B--->Hello A进行put02操作 B--->nihao A进行put03操作 B--->xiexie */ } }
2021年02月14日
64 阅读
0 评论
0 点赞
2021-02-14
ReadWriteLock读写锁
读写锁ReadWriteLock读写锁,一个用于只读操作,一个用于写入package com.sw.readWriteLock; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @Author suaxi * @Date 2021/2/14 0:10 * ReadWriteLock 读写锁 * 独占锁(写) 一次只能被一个线程占有 * 共享锁(读) 可以被多个线程同时占有 * 读-读 可以共存 * 读-写 不能共存 * 写-写 不能共存 */ public class ReadWriteLockTest { public static void main(String[] args) { MyCacheLock myCache = new MyCacheLock(); for (int i = 1; i <= 5 ; i++) { final int temp = i; new Thread(() ->{ myCache.put(temp+"",temp+""); },String.valueOf(i)).start(); } for (int i = 1; i <= 5 ; i++) { final int temp = i; new Thread(() ->{ myCache.get(temp+""); },String.valueOf(i)).start(); } } } class MyCacheLock{ private volatile Map<String,Object> map = new HashMap<>(); //相比于之前的lock锁,此处对线程的控制更加细粒度 private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //存 写 public void put(String key,Object value){ try { readWriteLock.writeLock().lock(); 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){ try { readWriteLock.readLock().lock(); System.out.println(Thread.currentThread().getName()+"读取---"+key); map.get(key); System.out.println(Thread.currentThread().getName()+"读取完成"); }catch (Exception e){ e.printStackTrace(); }finally { readWriteLock.readLock().unlock(); } } } class MyCache{ private volatile Map<String,Object> map = new HashMap<>(); //存 写 public void put(String key,Object value){ System.out.println(Thread.currentThread().getName()+"写入---"+key); map.put(key, value); System.out.println(Thread.currentThread().getName()+"写入完成"); } //取 读 public void get(String key){ System.out.println(Thread.currentThread().getName()+"读取---"+key); map.get(key); System.out.println(Thread.currentThread().getName()+"读取完成"); } }未使用读写锁之前,存在线程占用的问题:使用读写锁之后,执行顺序为:A写入--->A写入完成,B写入--->B写入完成,依次进行
2021年02月14日
119 阅读
0 评论
0 点赞
2021-02-12
JUC常用的辅助类
常用的辅助类1、CountDownLatch允许一个或多个线程等待其他线程完成操作package com.sw.assist; import java.util.concurrent.CountDownLatch; /** * @Author suaxi * @Date 2021/2/12 21:41 * <p> * assist 辅助类 */ //减法计数器 public class CountDownLatchTest { public static void main(String[] args) throws InterruptedException { //总数为6 CountDownLatch countDownLatch = new CountDownLatch(6); for (int i = 1; i <= 6; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + "--->走出教室"); countDownLatch.countDown(); //数量减1 }, String.valueOf(i)).start(); } countDownLatch.await(); //等待计数器归零,再向下执行 System.out.println("学生放学离开教室,班长锁门"); } } CountDownLatch原理:countDownLatch.countDown(); //数量减1countDownLatch.await(); //等待计数器归零,再向下执行执行方法,线程调用countDown();,使计数器数量减1,当计数器变为0时,countDownLatch.await();就会被唤醒,继续执行方法2、CyclicBarrier实现一组线程互相等待,当所有的线程都到达某个屏障点后再进行后续的操作package com.sw.assist; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * @Author suaxi * @Date 2021/2/12 21:56 */ //加法计数器 public class CyclicBarrierTest { public static void main(String[] args) { //10个学生都到教室后,老师才开始上课 CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> { System.out.println("孙老师开始上课"); }); for (int i = 1; i <= 10; i++) { //注:lambda表达式不能直接操作for循环中的i,它只是简化了new对象的过程 final int temp = i; new Thread(() -> { System.out.println(Thread.currentThread().getName() + "学生" + temp + "进入教室"); try { cyclicBarrier.await(); //等待 } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }).start(); } } } 3、Semaphore可以控制同时访问线程的个数package com.sw.assist; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/2/12 22:10 */ //停车位 public class SemaphoreTest { public static void main(String[] args) { //线程数量:提供3个停车位 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(3); System.out.println(Thread.currentThread().getName() + "---离开停车位"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); //释放 } }, String.valueOf(i)).start(); } } } semaphore.acquire(); //得到,如果当前提供的线程已经满了,则等待,直到线程被释放semaphore.release(); //释放,释放当前的信号量,然后唤醒等待的线程作用:多个共享资源互斥的使用;并发限流(控制最大线程数)
2021年02月12日
114 阅读
0 评论
0 点赞
2021-02-12
Callable()
Callable()可以有返回值,可以抛出异常Callable通过Runnable接口的实现类FetuerTask调用线程package com.sw.callable; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * @Author suaxi * @Date 2021/2/12 21:24 */ public class callableTest { public static void main(String[] args) throws ExecutionException, InterruptedException { MyThread thread = new MyThread(); FutureTask futureTask = new FutureTask(thread); //适配类 new Thread(futureTask,"A").start(); new Thread(futureTask,"B").start(); /* call()方法测试 泛型的参数 = 方法的返回值 相同的两个线程运行后只返回一个结果(有缓存) */ Object o = futureTask.get(); //获取callable返回值,此处的get可能会产生阻塞,接收返回值时可能需要等待 System.out.println(o); } } class MyThread implements Callable<String>{ @Override public String call(){ System.out.println("call()方法测试"); return "泛型的参数 = 方法的返回值"; } }
2021年02月12日
120 阅读
0 评论
0 点赞
2021-01-06
集合不安全问题
集合类不安全List不安全package com.sw.unsafe; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; /** * @Author suaxi * @Date 2021/1/4 17:12 * java.util.ConcurrentModificationException 并发修改异常 */ public class ListTest { public static void main(String[] args) { /* 并发情况下ArrayList不安全 解决方案: 1、List<String> list = new Vector<>(); 2、List<String> list = Collections.synchronizedList(new ArrayList<>()); 3、List<String> list = new CopyOnWriteArrayList<>(); CopyOnWrite 写入时复制(是一种优化策略) 多个线程调用的时候可能存在写入覆盖问题,读取没问题 CopyOnWrite在写入的时候复制一份给调用者,调用者写入新的数据完成之 后再把之前复制的数据放回原来的位置,保证线程的安全,以此避免了写入覆盖问题 相较于Vector,它没有采用synchronized锁,而是采用Lock锁,效率更高 */ List<String> list = new CopyOnWriteArrayList<>(); for (int i = 0; i < 100; i++) { new Thread(() ->{ list.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(list); },String.valueOf(i)).start(); } } } Set不安全package com.sw.unsafe; import java.util.*; import java.util.concurrent.CopyOnWriteArraySet; /** * @Author suaxi * @Date 2021/1/4 22:08 * java.util.ConcurrentModificationException 并发修改异常 * 解决方法: * 1、Set<String> set = Collections.synchronizedSet(new HashSet<>()); * 2、Set<String> set = new CopyOnWriteArraySet<>(); */ public class SetTest { public static void main(String[] args) { Set<String> set = new CopyOnWriteArraySet<>(); for (int i = 0; i < 30; i++) { new Thread(() ->{ set.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(set); },String.valueOf(i)).start(); } } } hashSet底层是什么?public HashSet(){ map = new HashMap<>(); } //源码 //set add的本质就是map public boolean add(E e) { return map.put(e, PRESENT)==null; } //PRESENT是静态终类 private static final Object PRESENT = new Object();Map不安全package com.sw.unsafe; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** * @Author suaxi * @Date 2021/1/4 22:26 * java.util.ConcurrentModificationException * 解决方法: * Map<String, String> map = new ConcurrentHashMap<>(); */ public class MapTest { public static void main(String[] args) { //默认等价于? new HashMap<>(16,0.75); Map<String, String> map = new ConcurrentHashMap<>(); for (int i = 0; i < 30; i++) { new Thread(() ->{ map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5)); System.out.println(map); },String.valueOf(i)).start(); } } }
2021年01月06日
691 阅读
0 评论
0 点赞
2021-01-06
8锁问题
8锁问题什么是锁?锁的对象是谁?package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 15:44 * 1、执行顺序:发短信 打电话 * 2、增加睡眠时间后,执行顺序:发短信 打电话 */ public class Test1 { public static void main(String[] args) { Phone1 phone1 = new Phone1(); new Thread(() ->{ phone1.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone1.call(); },"B").start(); } } class Phone1{ //synchronized锁的对象是方法的调用者 //两个方法用的是同一个锁,谁先拿到锁,谁先调用 public synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } public synchronized void call(){ System.out.println("打电话"); } }package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 15:51 * 3、增加一个hello的普通方法后,执行顺序为 hello 发短信 * 4、两个对象、两个同步方式,执行顺序为 打电话 发短信 */ public class Test2 { public static void main(String[] args) { //两个对象、两个调用者、两把锁 Phone2 phone1 = new Phone2(); Phone2 phone2 = new Phone2(); new Thread(() ->{ phone1.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone2.call(); },"B").start(); } } class Phone2{ //synchronized锁的对象是方法的调用者 public synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } public synchronized void call(){ System.out.println("打电话"); } //普通方法不受锁的限制 public void hello(){ System.out.println("hello"); } }package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 15:58 * 5、增加static后,执行顺序为 发短信 打电话 * 6、两个Phone对象,执行顺序依然为为 发短信 打电话 */ public class Test3 { public static void main(String[] args) { //两个对象的Class类模板只有一个,与问题5一样锁的也是Class Phone3 phone = new Phone3(); Phone3 phone1 = new Phone3(); new Thread(() ->{ phone.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone1.call(); },"B").start(); } } class Phone3{ //synchronized锁的对象是方法的调用者 //static静态方法,类一加载就有了,此处锁的是Class对象 public static synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } public static synchronized void call(){ System.out.println("打电话"); } }package com.sw.lock8; import java.util.concurrent.TimeUnit; /** * @Author suaxi * @Date 2021/1/4 16:05 * 7、1个静态同步方法,1个普通同步方法,一个对象,执行顺序 打电话 发短信 * 8、1个静态同步方法,1个普通同步方法,两个对象,执行顺序 打电话 发短信 */ public class Test4 { public static void main(String[] args) { //两个对象的Class类模板只有一个,与问题5一样锁的也是Class Phone4 phone1 = new Phone4(); Phone4 phone2 = new Phone4(); new Thread(() ->{ phone1.sms(); },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() ->{ phone2.call(); },"B").start(); } } class Phone4{ //静态同步方法 锁的是Class类模板 public static synchronized void sms(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发短信"); } //普通同步方法 锁的是调用者,不需要再等待发短信的sleep睡眠时间,两个方法用的不是同一个锁 public synchronized void call(){ System.out.println("打电话"); } }小结一个对象,拿的是同一把锁两个对象拿的是不同的锁加了static静态方法之后,不论有几个对象,锁的只有一个Class模板普通方法不受锁的限制
2021年01月06日
194 阅读
0 评论
0 点赞
2021-01-06
生产者和消费者问题
生产者和消费者问题package com.sw.pc; /** * @Author suaxi * @Date 2021/1/4 14:25 */ public class A { public static void main(String[] args) { Data data = new Data(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); } } class Data{ private int num = 0; //+1 public synchronized void incr() throws InterruptedException { if (num!=0){ //等待 this.wait(); } num++; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } //-1 public synchronized void decr() throws InterruptedException { if (num==0){ //等待 this.wait(); } num--; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } } 当增加多个线程时(A,B,C,D),会出现虚假唤醒的问题虚假唤醒:线程可以被唤醒,但不会被通知、中断或超时解决方法:将if判断换为whilepackage com.sw.pc; /** * @Author suaxi * @Date 2021/1/4 14:25 */ public class A { public static void main(String[] args) { Data data = new Data(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"C").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"D").start(); } } class Data{ private int num = 0; //+1 public synchronized void incr() throws InterruptedException { while (num!=0){ //等待 this.wait(); } num++; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } //-1 public synchronized void decr() throws InterruptedException { while (num==0){ //等待 this.wait(); } num--; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 this.notifyAll(); } } JUC版生产者消费者问题使用了Condition接口下的await()等待和signalAll()通知package com.sw.pc; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author suaxi * @Date 2021/1/4 14:55 */ public class B { public static void main(String[] args) { Data1 data1 = new Data1(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"C").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { try { data1.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } },"D").start(); } } class Data1{ private int num = 0; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //+1 public void incr() throws InterruptedException { try { lock.lock(); //加锁 while (num!=0){ //等待 condition.await(); } num++; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } //-1 public void decr() throws InterruptedException { try { lock.lock(); //加锁 while (num==0){ //等待 condition.await(); } num--; System.out.println(Thread.currentThread().getName()+"===>"+num); //通知 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } }Condition精准通知与线程唤醒可以看到之前的线程执行顺序是无序的。package com.sw.pc; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author suaxi * @Date 2021/1/4 15:08 * Condition精准通知与线程唤醒 * ABC三个人互相打电话,A->B,B->C,C->A顺序执行 */ public class C { public static void main(String[] args) { Data2 data2 = new Data2(); new Thread(() ->{ for (int i = 0; i < 10; i++) { data2.CallA(); } },"A").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { data2.CallB(); } },"B").start(); new Thread(() ->{ for (int i = 0; i < 10; i++) { data2.CallC(); } },"C").start(); } } class Data2{ private int num = 1; // 1A 2B 3C private Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); public void CallA(){ try { lock.lock(); //加锁 while (num!=1){ //等待 condition1.await(); } num = 2; System.out.println(Thread.currentThread().getName()+"===>A打完了"); //通知 condition2.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } public void CallB(){ try { lock.lock(); //加锁 while (num!=2){ //等待 condition2.await(); } num = 3; System.out.println(Thread.currentThread().getName()+"===>B打完了"); //通知 condition3.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } public void CallC(){ try { lock.lock(); //加锁 while (num!=3){ //等待 condition3.await(); } num = 1; System.out.println(Thread.currentThread().getName()+"===>C打完了"); //通知 condition1.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); //解锁 } } } 通过不同的监视器监视线程来达到精准通知与线程唤醒的目的
2021年01月06日
204 阅读
0 评论
0 点赞
1
2
3