一.synchronized和Lock:
synchronized:有一个共享资源,我们只允许一次一个线程访问它。把所有能访问该资源的方法都封装到一个类中,然后把这些方法全都加上synchronized关键字,如果这时候有一个线程正在调用一个该关键字标记的方法,那么当这个线程从该方法返回之前,其他所有要调用该关键字所标记的方法的线程都会被阻塞。
https://www.jianshu.com/p/b1581c35c881 //这个网址讲锁讲的特别好
lock:
synchronied和lock的比较:
再解决以后
synchronized的缺陷:
有两种情况可以让一个执行synchronized修饰的方法的线程退出,一是执行完毕,二是线程执行发生异常,JVM会让线程自动释放锁。。。。。。所以如果这个线程由于等待IO或者其他情况(比如sleep方法)被阻塞而又没有释放锁,那么其他想操作这个锁的线层就要一直等下去。 再比如“读操作”,这个操作是可以多个线程同时执行的。你synchronized关键字就做不到,Lock可以
Lock必须手动释放,否则容易造成死锁,而synchronized关键字不需要手动释放,执行完他自己就释放了
Lock是个接口 而synchronized是java内置的关键字
通过Lock可以获取有没有获得锁,而synchronized则不能
Lock可以提高多个线程获得锁的效率
二.线程的五大状态:
1.新建
2.就绪
3.运行
4.阻塞
5.死亡
三:java当中的死锁举例:
public class DeadLockTest
{
private static Object A = new Object(), B = new Object();
public static void main(String[] args)
{
new Thread(() -> {
System.out.println("线程1开始执行...");
synchronized (A)
{
try
{
System.out.println("线程1拿到A锁");
//休眠两秒让线程2有时间拿到B锁
Thread.sleep(2000);
} catch (Exception e)
{
e.printStackTrace();
}
synchronized (B)
{
System.out.println("线程1拿到B锁");
}
}
}).start();
new Thread(() -> {
System.out.println("线程2开始执行...");
synchronized (B)
{
try
{
System.out.println("线程2拿到B锁");
//休眠两秒让线程1有时间拿到A锁
Thread.sleep(2000);
} catch (Exception e)
{
e.printStackTrace();
}
synchronized (A)
{
System.out.println("线程2拿到A锁");
}
}
}).start();
}
}
四.violate关键字
https://blog.csdn.net/yinbucheng/article/details/71305951
五:乐观锁和悲观锁
悲观锁:总是假设最坏的情况,认为每次拿数据都会有别人过来修改,所以每次拿数据都会加锁,等自己操作完成后才会释放,然后给其他线程机会,比如syncronized就是悲观锁
乐观锁:总是假设最好的情况,每次更新的时候都认为别人不会修改,所以都不加锁,但是更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用CAS算法来实现
两种锁的应用场景:
从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。