Synchronized和Lock锁的区别
1.Synchronized是内置的java关键字,Lock是java的一个类
2.Synchronized锁是自动释放的,Lock锁则需要手动解锁
3.Lock可以检查是否有锁,java.lang.Thread下的holdslock()方法,Synchronized不能
4.Synchronized可重入锁,不可以中断,非公平,Lock可重入锁,非公平(但可以更改)
5.Synchronized线程1(获得锁,阻塞),线程2(一直等),Lock不会一直等,会尝试获得锁trylock()
6.Synchronized适合锁少量代码同步问题,Lock适合锁大量同步代码
八锁问题
非静态方法的锁默认为this,静态方法的锁为对应的class实例(这里是Number.class)
某一个时刻内,只能有一个线程持有锁,无论有几个方法。
总结:
①一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其他的线程都只能等待,换句话说,某一时刻内,只能有唯一一个线程去访问这些synchronized方法。
②锁的是当前对象this,被锁定后,其他线程都不能进入到当前对象的其他的synchronized方法。
③加个普通方法后发现和同步锁无关。
④换成静态同步方法后,情况又变化
⑤所有的非静态同步方法用的都是同一把锁 – 实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已经取锁的非静态同步方法释放锁就可以获取他们自己的锁。
⑥所有的静态同步方法用的也是同一把锁 – 类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间不会有竞争条件。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们是同一个实例对象
Condition实现精准唤醒
可以在代码中加多个condition实现指定唤醒
condition.await() 使condition等待
condition.signal() 唤醒condition
常用辅助类
1.CountDownLatch(减法计数器)
await() 等待计数器完成
2.CyclicBarrier(加法计数器)
await() 等待计数器完成
3.Semaphore(信号量)
acquire() 得到
release() 释放
阻塞队列BlockingQueue的API
1.抛出异常
添加:add()
移除:remove()
检测队首元素:element()
2.不抛出异常,有返回值
添加:offer()
移除:poll()
检测队首元素:peek()
3.阻塞 等待
添加:put()
移除:take()
4.超时 等待
添加:offer(, ,)
移除:poll(,)
线程池
三个方法
Executors.newSingleThreadExecutor() //单个线程
Executors.newFixedThreadPool(int nThreads) //创建一个固定的线程池的大小
Executors.newCachedThreadPool() //缓存池,可伸缩的, 遇强则强,遇弱则弱
七个参数
public ThreadPoolExecutor(int corePoolSize, //核心线程池大小
int maximumPoolSize, //最大核心线程池大小
long keepAliveTime, //超时了没有人调用就会释放
TimeUnit unit, //超时单位
BlockingQueue<Runnable> workQueue, //阻塞队列
ThreadFactory threadFactory, //线程工厂,创建线程的,一般不用动
RejectedExecutionHandler handler) //拒绝策略
四个拒绝策略
- new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人进来,不处理这个人的,抛出异常
- new ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里!
- new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
- new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试和最早的竞争,也不会抛出异常
四大函数式接口
函数型接口:
Function<T, R>
传入一个参数T,返回R
public static void main(String[] args) {
Function function = new Function<String, String>() {
@Override
public String apply(String s) {
return s;
}
};
// 只要是函数式接口,就可以使用lambda表达式简化
Function function1 = a -> {
return a;
};
System.out.println(function.apply("WWWW") + "====" + function1.apply("XXXX"));
}
断定型接口:
Predicate
传入一个参数,返回一个布尔值
public static void main(String[] args) {
// 传入一个参数,返回一个boolean值
Predicate predicate = new Predicate<String>() {
@Override
public boolean test(String s) {
return false;
}
};
// 只要是函数式接口,就可以使用lambda表达式简化
Predicate predicate1 = a -> {
return false;
};
System.out.println(predicate.test("a") + "====" + predicate1.test("b"));
}
消费型接口:
Consumer
传入一个参数,没有返回值
public static void main(String[] args) {
Consumer consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
// 只要是函数式接口,就可以使用lambda表达式简化
Consumer consumer1 = a -> {
System.out.println(a);
};
consumer.accept("s");
consumer1.accept("a");
}
供给型接口:
Supplier
不传入参数,返回一个值
public static void main(String[] args) {
Supplier supplier = new Supplier() {
@Override
public String get() {
return "aaa";
}
};
// 只要是函数式接口,就可以使用lambda表达式简化
Supplier supplier1 = () -> {
return "bbb";
};
supplier.get();
supplier1.get();
}
谈谈对Volatile的理解
1.保证了可见性
2.不保证原子性
3.防止指令重排序
单例模式
(详见收藏夹)
1.饿汉式单例
2.DCL懒汉式单例