多线程(一)
1、同步方法和非同步方法是否可以同时调用? 是
===========================
2、银行账户余额,如果对写操作加锁,对读操作不加锁,会产生脏读的问题。
=======================================
3、一个同步方法可以调用另一个同步方法,synchronized是可重入的。子类synchronized可以调用父类的synchronized方法
=============================================================================
4、sychronized方法出现异常时,锁会被释放
==============================
5、volatile(线程之间的可见性) cpu写入内存后通知其他线程更新数据。
============================================
6、volatile和synchronzied区别:
==============================
volatile只保证可见性,不保证原子性。synchronized既保证可见性,又保证原子性,但是效率比volatile慢很多。
7、AtomicInteger
===================
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();
AtomicInteger比sychrnized更高效
8、synchronzied同步块中的语句越少越好
=============================
只给需要的语句加锁,采用细粒度的锁,可以是线程征用时间变短,从而调高效率
9、锁定某对象O,如果O的属性发生改变,不影响锁的使用。但是如果O变成另外一个对象,则锁定的对象发生改变。应该避免将锁定对象的引用变成另外的对象
============================================================================
10、不要用字符串常量作为锁定对象
=====================
String s1="hello";
String s2="hello";
s1==s2 true;这两个是一个对象。
所以在字符串常量上加锁,如果值相同,则会锁定同一个对象。则会产生死锁阻塞
11、wait notify
==================
wait()方法让该进程进入等待状态,notify()唤醒等待的一个进程。
两者都需要写在里面synchronized(object){},wait会释放锁,notify不会释放锁。
12、CountDwomLatch
=====================
不需要synchronized锁定,直接用
CountDowmLatch latch = new CountDownLatch(1); //countDown 1次 门栓就开了
latch.await(); 等待
latch.countDown(); //值减一 。值为0时 唤醒一个等待线程
13、ReentrantLock
====================
Lock lock = new ReentrantLock();
lock.lock();
lock.lockInterruptibly(); lock和lockInterruptibly都会等待一把锁,但是lockInterruptibly可以被其他线程打断,但是lock不可以被打断(会一直等)
lock.unlock();
使用synchronized的话如果遇到异常,jvm会自动释放锁,但是lock必须手工释放锁,因此经常在finally中进行锁的释放。
boolean locked = lock.tryLock(5,TimeUnit.SECONDS);尝试申请锁 5秒钟,如果5S内申请不到,不再申请。
很多线程竞争锁时是否公平 ,不按等待时间来分配锁 视为不公平,分为公平锁和不公平锁(公平锁是谁等的时间长谁获先 得锁)。
不公平锁比公平锁效率高
synchronized 是不公平锁,
14、生产者消费者
=============
14.1 synchronized notifyAll wait
14.2 ReentrantLock
15、ThreadLocal
==================
ThreadLocal 它并不是为了解决多线程共享变量的问题,比如商品的库存数量这种场景下是不能使用 ThreadLocal 的。ThreadLocal 是多线程都需要使用一个变量,但是这个变量的值不需要各个线程间共享,每个线程都有自己的这个变量的值。
16、线程安全的Singleton
=====================
https://www.cnblogs.com/xudong-bupt/p/3433643.html
17、ConcurrentLinkedQueue多线程容器
=================================
比加锁效率高。
18、并发容器
===========
ConcurrentHashMap<>() ConcurrentSkipListMap<>() https://blog.csdn.net/sunxianghuang/article/details/52221913(跳表)
不要求并发,不加锁
hashmap
treemap
linkedhashmap
并发性不是特别高的情况下使用:
HashTable(支持同步,线程安全)
Collections.synchronizedXXX
并发性特别高的情况下使用:
concurrenthashmap(无需)
concurrentskiplistmap(有序)https://blog.csdn.net/sunxianghuang/article/details/52221913
19、写时复制容器(写的效率非常低,读的效率非常高)
==============================
CopyOnWriteArrayList<>(); 写入数据时会复制数据,把引用指到新的地方。读数据的时候不用加锁的,读的就是新数据。
20、Executor
===============
Executor
ExecutorService submit
Callable = Runnable Callable有返回值 泛型
Executors 工具类 操作Executor
21、线程池
==========
Executors._newFixedThreadPool_(5);
启动一个具有5个线程的线程池,添加6个线程,其中会有一个进入等待队列(还有一个已完成队列),可以看到console打印的信息。
shutdown一个线程池,线程不会Terminated,因为任务还没执行完,只是线程池状态变成shutting down,执行完了状态变为Terminated
22、Future
=============
===================================================================
23、Excutors.newCachedThreadPool
===================================
刚开始一个线程都没有,来一个任务就启动一个线程。每来一个任务,如果线程池中有空闲的线程,则使用空闲的线程,如果没有,则新启动一个线程。知道线程数到达系统所能支撑的最大线程数。
默认情况下,只要空闲的线程空闲时间超过60秒,就会自动销毁。Alivetime也可以自动指定
24、Excutors.newSingleThreadPool
===================================
线程池中永远只有一个线程--(保证任务一定是顺序执行的)
25、Excutors.newScheduledThreadPool(4)
=========================================
scheduleAtFixedRate 一共四个参数 (匿名内部类(lambda表达式)指定要执行的任务,第一个任务的延迟执行时间,每隔多长时间执行下一个任务,时间的单位(秒 毫秒 ))
26、Excutors.newWorkStealingPool()
=====================================
线程池中每个线程执行完任务之后,不需要给它分配新任务,这些线程会自己找任务来执行。而上面的几种线程池,每个线程执行完任务后,要等待分配任务。
27、ForkJoinPool
===================
线程池关系图
总结:
比较
======
线程生命周期
==========
解决线程安全
==========
死锁避免
========
1、有序资源分配法
2、银行家算法
3、顺序加锁
4、限时加锁
死锁检测
========
死锁恢复
========
Java内存模型
多线程特性
CAS原理:
htt[ps://www.bilibili.com/video/av56465131?p=39](http://ps://www.bilibili.com/video/av56465131?p=39
)
[](http://ps://www.bilibili.com/video/av56465131?p=39
)