同步关键字synchronized
注:本博文synchronized 有时会简写成 sync
synchronized 同步关键字,自动释放锁,锁住的是对象,不是代码块
sync 声明在方法名上,锁定的是this对象(调用方法的那个对象)
sync 锁是可重入的(此线程可多次访问此对象的锁)
本方法再次调用本方法
本方法调用父类方法
死锁的模拟
线程T1 持有锁A 等待B
线程T2 持有锁B 等待A
可见性关键字volatile
volatile 保障可见性,不能代替sync,不能保障原子性,性能比sync高
下面场景:
主线程变量 V
线程1 读变量V,继续跑一段时间
线程2 写变量V,并同步至主线程
现场1 读V,还是原来的V,原因是读的是此线程对变量的副本。
加了volatile之后,线程2对比那里V做的修改,线程1也可以看见。
wait-notify
wait 让线程进入等待状态,同时释放锁,直到其它线程notify时,它才会重新运行。Object的方法,wait需要和while共用
notify 唤醒一个线程,但是不会释放锁,如果本身拿着对象的锁,wait也不会唤醒其他线程
notifyAll 唤醒所有wait的线程,所以这里也是说要用wait和while搭配的原因。
A object.wait() //释放锁
B object.nofity() //唤醒object锁的线程,此时没有释放锁
B object.wait() //释放此线程的锁
A 执行 //得到锁 可以运行业务方法
A object.notity() //结束时唤醒object 锁的线程
简单示例:https://blog.csdn.net/xiaoluo5238/article/details/104358061
重入锁ReentrantLock
ReentrantLock 重入锁 可以实现 sync ,比sync灵活,需要手动释放锁
new ReentrantLock();//随机分配锁
new ReentrantLock(true);//声明公平锁 等待时间越长,得到锁的优先级越高
lock.lock();//申请
lock.unlock();//释放锁
bool lockFlag = lock.tryLock();//尝试去拿锁,返回lock,如果为true,说明拿到锁,需要解锁
bool lockFlag = lock.tryLock(5, TimeUnit.MINUTES);//尝试去拿锁,等待5分钟
lock.lockInterruptibly(); 可被打断的等待锁,主线程调用此线程的 interrupt 方法。
Lock的Condition 使用Condition的await()、signal()/signalAll() 代替 wait/notify,这种方式实现线程间协作更加安全和高效
Condition putCondition = lock.newCondition();//实例
putCondition.await();//与Object.wait方法一样,都是要与while共同使用,使线程等待,释放锁,直到putCondition.signal()或
putCondition.signalAll()才继续执行
putCondition.signal();//唤醒 putCondition.await() 等待的线程
简单示例:https://blog.csdn.net/xiaoluo5238/article/details/104348598
Condition示例:https://blog.csdn.net/xiaoluo5238/article/details/104359334
ThreadLocal
ThreadLocal
线程内 threadLocal.set(), 只是当前线程能 threadLocal.get() 到
只能设置一个对象,可set map对象。
容易造成内存泄漏,每次使用完ThreadLocal,都调用它的remove()方法,清除数据
简单示例:https://blog.csdn.net/xiaoluo5238/article/details/104360178
多线程同步工具
CountDownLatch 线程间的通讯 -门栓 或 门闸 或 减数器
简单理解:等待 所有的门栓 打开后才能继续执行
new CountDownLatch(3);//声明定义 多少个门栓,如果有3个,那个需要调用3次countDown()方法后,才能执行到await()方法
countDownLatch.await(); //等待门栓全部打开,才会执行
countDownLatch.countDown();//打开一个门栓
简单示例:https://blog.csdn.net/xiaoluo5238/article/details/104339788
Semaphore 信号量 信号量是保证同一时间内最大的访问数量(线程)
Semaphore semaphore = new Semaphore(2);//同时申请的数量
semaphore.acquire();//申请信号量
semaphore.release();//释放信号量
简单示例:https://blog.csdn.net/xiaoluo5238/article/details/80310436
CyclicBarrier 循环栅栏
new CyclicBarrier(num);//设置栅栏数
new CyclicBarrier(num,Runnable)//设置栅栏数(目标数),并且达到目标后做的事情
cyclicBarrier.await();//到达栅栏,让线程等待,等到有足够多到达栅栏的任务才会继续往下走。栅栏是循环的。
简单示例:https://blog.csdn.net/xiaoluo5238/article/details/104382801
多线程队列
队列分为 阻塞队列和非阻塞队列两种,阻塞队列里面又有很多很有趣的衍生。
Queue 基本方法如下:
add();//如果队列已满,会抛出错误
offer();//相当于add,如果队列已满,返回false
remove();//删除第一个元素,集合为空时调用抛出异常
poll();//删除第一个元素,集合为空时调用,返回null
peek();//查询队列头部元素,空时null
element();//查询队列头元素,空时报错
ConcurrentLinkedQueue 非阻塞队列
ConcurrentLinkedDeque 双端队列 多了从第一个和从最后一个的操作方法:的方法如:offerFirst offerLast pollFirst pollLast
BlockingQueue 阻塞队列
比Queue新增了:
put();//如果满了,就会等待
take();//如果空了,就会等待
blockingQueue.offer("123",10,TimeUnit.MINUTES);//添加,如果添加不成功,10分钟后,程序阻塞
LinkedBlockingQueue 阻塞队列 列表
ArrayBlockingQueue 阻塞队列 数组,要声明队列长度
DelayQueue 延迟队列,执行定时任务,只能添加实现了 Delayed接口的对象
LinkedTransferQueue 等待消费者消费才能进行生产,有消费者时它会直接找消费者,没有就阻塞
transferQueue.transfer(); 与add/offer 生产者生产,如果无消费者,它会阻塞
SynchronousQueue 继承 TransferQueue,容量为0的队列,只能有put,只有消费者消费完之后才能进行put
简单示例:https://blog.csdn.net/xiaoluo5238/article/details/104374753
多线程线程池
Executor 线程的执行
ExecutorService 执行任务的服务
submit();//可以有返回值,可以传 Runnable/Callable 任务
execute();//执行任务方法,无返回值。可以传Runnable任务
shutdown();//关闭,会等所有线程都跑完后关闭线程池
Callable 是线程来调用的,有返回值的
Runnable 线程来调用,没有返回值
Executors 操作Executor的工具类,里面有很多静态方法(类比 Arrays是Array的工具类)
ThreadPool 线程池 线程池内的线程是循环使用的,线程不会消失
//固定个数线程池
ExecutorService fixThreadPool = Executors.newFixedThreadPool(5);
//弹性线程 60秒线程不执行任务 自动消失 ,无线程上限数量
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
//每次只执行一个线程,线程前后执行
ExecutorService singleThread = Executors.newSingleThreadExecutor();
//定时执行
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);
//利用所有运行的处理器数目来创建一个工作窃取的线程池 ,这个work下所有的任务执行完了,会偷其它work下的任务
ExecutorService work = Executors.newWorkStealingPool();
自定义线程池:
ThreadPoolExecutor(int corePoolSize, //主线程数量
int maximumPoolSize,//最大线程数量
long keepAliveTime,//当线程超过最大线程数量时,超过线程的持续时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue)//阻塞队列
Future 模式(使用线程池):https://blog.csdn.net/xiaoluo5238/article/details/81975710
线程池的使用:https://blog.csdn.net/xiaoluo5238/article/details/81976677