首页 > 编程知识 正文

nicu工作心得体会,ccu出科小结怎么写

时间:2023-05-03 19:54:46 阅读:154670 作者:654

这里包括io、集合类、常用类

1、什么是juc

这是java.util的三个工具包

1 ) java.util.concurrent

2 ) java.util.concurrent.atomic

3 ) java.util.concurrent.locks

2、为什么用juc

理由1 :有些项目无法通过普通的Thread和Runnable实现。 后者将在Thread静态代理上运行。 后者比前者灵活,但与callable相比效率较低,没有返回值,所以使用callable。 这是在juc下面。 Lock也在juc之下。

2、线程和进程

流程:例如,运行qq.exe时它就是一个流程,而在Java中运行jar包也是一个流程。 程序集合是静态的,运行时是动态的,也就是过程。

线程:一个进程包括多个线程,至少一个,但在Java中是缺省的两个线程。 分别是mian线程和gc线程。 前者是用户线程,后者是守护进程线程,守护进程线程随着用户线程的结束而结束。 在模拟生活中,打开qq后,在这个过程中可以启动歌唱线程,也可以启动学习线程。

3、并发和并行

并发:多线程操作是相同的资源,如果有一个cpu内核,它可以快速交替模拟多个线程。 (并发编程的本质:重用cpu资源,产品牛了一定要考虑性能。 因为它必然用于同时编程,所以必须做到)

并行:多核cpu允许多个线程同时运行,如线程池。 (多人行走)。

4、线程有几种状态

源代码中6种:安静黑米,运行,屏蔽,等待(一直等待),等待超时,结束

简而言之,应该是安静的黑米、运行、闭塞、结束四种状态。

5、wait和sleep区别

1 )来源不同

wait在Object类下

sleep在juc之下

2 )是否解除锁定

wait很冷静,所以解除锁定

sleep抱着锁睡觉,所以不释放锁

3 )使用场景不同

wit只能在同步代码块中使用(需要某个人)。

sleep可以在任何地方使用(一个人随时随地睡觉) )

4 )收到异常了吗

1 ) wait不需要捕获异常

2 ) sleep必须捕捉异常

6、传统的Synchronized锁

写三个人卖票的代码

以前通过编写Ticket类实现Runnable接口,现在添加了一种卖票的方法,即写总票加模式数属性。 然后,用main函数在new Thread方法中插入Runnable并执行start方法;

但是,在实际项目中,由于绑定,所以不会让Ticket类实现Runnable接口。 要实现这个效果,只需在main函数的new Thread中直接使用Runnable的lambda表达式即可。 for循环也写在这里。 如下所示。

但是,很明显,这个代码是有线的、安全的,所以可以在Ticket类售票这个方法之前加上sychronzied。

7、Lock锁

Lock是juc下的接口,因此必须使用实现类。 典型的实现类是可重新锁定的ReentrantLock。

Lock lock=new ReentrantLock ()

(如果改成自带结构,加上true的话,就会变成公平锁定。 先来先执行,其实这不公平。 先来的运行3h,后来的只有3m,所以一定要在后面。 所以,一般不附加参数就使用默认的不公平锁。 ) ) ) ) ) ) ) ) 652 )

然后,在上面售票示例的Ticket类中,售票方法为try-catch-finally,try为lock.lock,最后为finally解除lock.unlock。

8、同步和锁定的区别

1 )来源

同步是内置关键字

Lock是juc的类

2 )能否判断获取锁的状态

无法判断同步

Lock可以判断

3 )是否自动解锁

同步会自动解除锁定

锁定不会自动解除锁定。 必须手动解除。 否则你会陷入死锁。

4 )是否可以设置为公平锁

synchronized缺省为不公平锁,无法设置

Lock可以设定,在new的情况下将参数设为true即可

5 )应用场景

同步适合于锁定少量的代码同步问题

Lock适合锁定大量的代码同步问题

注:两者都是可以重新锁定的,这一点是相同的。

9、生产者消费者模式

要完成模型,必须实现线程通信

1 ) synchronzied版本采用wait和notifyAll方法,但考虑到两个或多个线程同时加减会出现虚假唤醒问题,因此使用while而不是if

2 )摇滚版本

synchronzied将被lock和unclock方法替换,wait和notifyAll将被什么替换? Lock实现类ReentrantLock中的Condition方法获取一个Condition对象,该对象中的await方法将代替wait方法,而signalAll方法将代替

代notifyAll方法。
思考一下,为什么出现Condition(条件)?
(新技术出现肯定有原因,肯定不是完全覆盖原技术,大概率是有新优势和补充!)
让ABCD两对生产消费者能有序执行即精准的通知和唤醒线程!(而sychonzied不行)
如何实现?写多个Condition对象,然后在各自方法中await不变,只是之前同一个Condition的notifyAll改成下一个Condition的notify。
9、8锁现象
什么是锁,锁的是谁?
只能锁对象和class(前者多个,后者唯一)
8锁现象就是关于锁的8个问题
1)标准情况下,两个线程先打印发短信还是打电话?(这两个方法都是synchronized修饰的)
答:发短信先,因为锁只有一个,谁先拿到就谁先打印。
2)发短信延迟4秒情况下,两个线程先打印发短信还是打电话?(这两个方法都是synchronized修饰的)
答:还是短信先,只是延迟4秒后再打电话
3)现在新增一个普通方法hello(),然后替代main方法中的打电话,那先执行发短信还是hello?
答:普通方法先
4)两个对象,一个发短信(延迟4秒),另一个打电话(这两个方法都是synchronzied修饰的同步方法)
答:两个对象,两把锁,分开执行,所以打电话先。
5)在2的基础上变化两个同步方法为静态方法,然后判断先打印发短信还是打电话?
答:这里锁的是class对象,所以全局唯一,所以先发短信。
6)4的基础上把同步方法加上static,先打印发短信还是打电话?
答:发短信先,因为现在只有一个class对象锁,不再是两个。
7)一个静态同步方法,一个普通同步方法,一个对象,那先打印发短信还是打电话?
答:打电话先,因为两个方法不同锁,不需要等待。
8)7基础上把一个对象改成两个
答:还是打电话先,因为还是不同锁,不需要等待。
小结:
new this是具体对象,可以多个锁
static Class是唯一的一个模板,锁唯一
10、集合类不安全
1)List
多线程情况下,普通的ArrayList调用add方法,会报java.util.ConcurrentModificationException即并发修改异常!
所以并发下不能用ArrayList,必须加锁来保证安全,具体来说有三种解决方案:
A、使用最早的Vector类,内部add方法会加上synchronized保证线程安全;
B、使用所有集合工具类Collections的synchronizedList(new ArrayList<>())
C、使用juc包下的CopyOnWriteArrayList<>(),其底层用到Lock类和volidate关键字(后面会提到),思想类似Mycat读写分离,即复制集合写然后再放进去。
2)Set
Set和List都是Collection集合下的类(还有队列Queue也是集合下类),并发情况下add也会有抛出并发修改异常,为什么会?因为hashSet底层就是HashMap,其元素不可重复性就是用了map的key不重复特性,那如果使set线程安全?
B、Collections工具类下的synchronizedSet方法
C、juc包下的CopyOnWriteArraySet类
3)Map
HashMap默认的加载因子是0.75,默认容量是16,HashMap肯定线程不安全,具体可以单独总结,线程安全解决方法:
A、用Collections工具类中的SynchronizedMap方法
B、juc包下的ConcurrentHashMap
(这个底层原理后面单独总结)
11、Callable
Callable接口和Runnable接口区别
1)前者有返回值,后者没有
2)前者可以抛出异常,后者不行
3)前者用call方法,后者是run方法
Callable接口看起来比Runnable接口难,但其实二者有关系,FutureTask是Runnable的实现类,然后有参构造里可以是Callable,所以直接
new Thread(new FutureTask(Callable

)).start()即可,其中Callable要替换成实现Callable的实现类对象,这个实现类对象就是我们要写的。
12、常用的辅助类
1)CountDownLatch
比如计数器从6到0,做减法
2)CyclicBarrier
集齐7颗龙珠召唤神龙,做加法
3)Semaphore
6辆车抢3个车位
13、读写锁 ReadWriteLock
读的时候多个线程读
写的时候只有一个线程写
14、阻塞队列BlockingQueue
1)什么时候使用?
多线程、线程池
2)在哪里?
Collection下除了List和Set还有队列Queue,其实现类就包括阻塞队列BlockingQueue、非阻塞队列AbstractQueue,然后阻塞队列下面有LinkedBlockingQueue(链表)和ArrayBlockingQueue(数组)。
3)四组API
必须设置容量大小
A、抛出异常
添加 add
移除 remove
检测队首元素 element
B、有返回值,不抛出异常
添加offer
移除 poll
检测队首元素 peek
C、阻塞 一直等待
put
take
D、阻塞 超时等待
offer(,,)
poll(,)
4)SynchronousQueue 同步队列
没有容量,最多一个元素
进去一个元素,必须等待取出来之后,才能再往里面放一个元素!
put、take
15、线程池(重点)
1)池化技术
线程频繁创建销毁很浪费资源,所以引入池化技术,类似的有连接池、内存池等
线程池优点是减少频繁创建消费浪费资源,控制最大并发数、管理线程
2)线程池三大方法
调用Executors类以下三个方法
A、newSingleThreadExecutor()
单个线程,不管for循环几次都只有这一个线程执行
B、newFixedThreadPool(5)
固定线程数量,如果设为5则最多5个线程同时执行
C、newCachedThreadPool()
数量可伸缩,即遇强则强,遇弱则弱,由for循环的次数来决定最大线程数,比如for循环100次,则理论上会有100个线程同时执行,但具体数量根据电脑配置决定。
根据上面方法会获取一个类ExecutorService,那怎么执行这个类对象?直接调用该类对象的execute(Runnable)方法即可,参数中可以用lambda直接写run方法。
3)线程池七大参数
其实上面三个方法代码内部都是new ThreadPoolExecutor(7个参数),只是参数不同,那这7个参数分别是什么?
A、核心线程数,比如2
B、最大线程数,比如5
C、超时多少了没人调用就会释放(释放的是最大线程减去核心线程那几个线程),比如3
D、超时单位,比如秒
E、阻塞队列,比如new LinkedBlockingDeque<>(3)
F、线程工厂,一般默认,统一为Executors.defaultThreadFactory()
G、拒绝策略,一共四种,具体看后面
根据上面参数来说明线程池工作原理:
类似银行,一开始只有两个柜台(因为核心线程为2),如果for循环次数在2以内,则这两个完全可以完成任务,但如果2-5之间,则因为最大线程数为5,所以此时第三个人及其之后的人都要在候客区等待,如果for循环次数在6-8之间,则此时候客区也不够坐,需要开启3个临时窗口,即3个临时线程来办理业务,如果人少了,临时窗口超过3秒没人办理则会关闭;但如果人还越来越多那就开始使用拒绝策略,一共四种。
4)线程池四种拒绝策略
A、丢掉任务,并抛出异常
B、哪里来的回哪去,比如调用main线程执行
C、丢掉任务,不抛出异常
D、尝试和最早的竞争,失败也不抛出异常
注:阿里巴巴代码规范里提到不能用Executors三大方法直接创建线程池,因为可能造成oom不安全,建议用这些方法里的new ThreadPoolExecutor(7个参数)
5)池的线程数最大值如何设置
CPU密集型看电脑最大核数:Runtime.getRuntime().availableProcessors()
IO密集型看最大任务数,一般是其两倍
16、四大函数式接口(必须掌握)
传统java程序员必须会:
泛型、枚举和反射
新时代java程序员必须会:
lambda表达式
链式编程
函数式接口
stream流计算
这里主要讲下函数式接口,首先明确只有一个方法的接口就是函数式接口,而且这个接口上面会有注解@FunctionalInterface,主要有以下四种:
1)Function<T,R>
传入参数T,返回类型R
Function<String,String> function = new Function<String,String>(){
重写apply方法,输入str返回str
}
然后调用function的apply方法即可。
当然上面代码可以用lambda表达式简化:
Function function = (str) ->{return str;};
(只有str一个输入参数,则str的小括号也可以去掉)
2)Predicate 断定型接口
传入参数T,返回类型只能是布尔值
重写的方法是test方法,可以用于判断字符串是否为空,即断定型接口。
直接用lambda表达式:
Predicate predicate = (str)->{
return str.isEmpty();}
3)Consumer 消费型接口(和下面供给型接口相反)
只有输入参数,没有返回值
直接lambda表达式:
Consumer consumer = (str) -> {sout(str);};即直接打印输入参数
4)Supplier 供给型接口
没有输入参数,只有返回值
直接lambda表达式:
Supplier supplier = ()->{return 1024;};
17、stream流式计算
什么是stream流式计算?
大数据:存储+计算
我们学到能存储的东西有集合、mysql和fastdfs等
而计算都是交给流的,比如降序
sort(mdxm1,mdxm2)->{mdxm2.compareTo(mdxm1);};
其实底层用的都是函数式接口
18、ForkJoin

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。