锁专题(面试和实际工作)

乐观锁和悲观锁

悲观锁:
顾名思义:很悲观,感觉程序一定会出问题,所以在程序中加入锁。主要有:
    1、synchronized(有对象锁,类锁),
    对象锁,在synchronized关键字后的传入线程的共享对象。或者是在实力方法的中用synchronized关键字修饰。
    类锁,就是在静态方法中使用sychroniezd的关键字修饰。
    2、lock锁(实现类Reentrantlock)
    主要可以完成sychronid完成的一切工作,但是可以自由的控制什么时候释放锁,有更好的性能。

乐观锁:
顾名思义:很乐观啊,感觉程序很健壮,在什么时候都不会出问题。所以都不加锁。主要使用:
    1、数据库版本号机制:
    在数据库中一般都是使用innnodb数据库引擎,是行级锁,myisam是表级锁。安全但是效率低。
    在表中多添加一个字段version,当需要对某条数据进行修改操作的时候,就连同这个version字段一同取出。
    比如说对password字段进行修改,那么会将这个取出来的version值进行加一,然后再去原始的数据库中查看原始的version值。
    如果加一后的version值比数据库中的version值大,那么就进行修这条数据行。否则就修改失败。
    2、cas指令。
      比如说在内存中有一个共享变量i=0,有两个线程想要操作这块数据。
      如果说,A线程抢到cpu执行权。读取主内存中的共享变量i=0, 那么就把这个共享变量i=0的副本保存到线程A的本地内存中。
          然后开始对 i +1操作。
          而这个时候,A的cpu时间片执行完了,回到就绪状态,
          
          而线程B抢到了cpu执行权,开始执行对主内存中共享变量i的操作
          线程B也把i=0保存到自己的本地内存中,然后进行i+1操作,得到 i=1;然后再去主内存中读取共享变量i=0。
          线程B发现两次读取主内存中共享变量的值一样,那么就主内存中的共享变量的i的值修改为1。


公平锁和非公平锁

主要是在lock()方法上传一个true/false就可以实现公平锁,和非公平锁。
    公平锁:
    公平锁就是在线程同步的基础上,一个个线程排着队。
    当一个线程拿到了对象锁之后执行程序,释放对象锁之后,就能再去使用使用cpu的空闲时间去执行。
    非公平锁:
    就是在释放掉对象锁的时候,其他线程还没来得及执行的时候,又去执行了程序。
    比如说:排队挂号。你排完队走了,轮到下一个人挂号了,但是又有事想问挂号人员。
    这个时候你在下一个人还没开始办理业务的,你又问了一句,这个科室在几楼。这就是非公平锁。
=========================================================================

死锁和活锁

    死锁:原因是竞争太激烈了。谁也不想放掉手里的资源。还都想得到对方的资源。
    一个很好的成语更好的描述死锁。鹬蚌相争。
    比如说连个线程A B 同时共享 两个共享对象o1 o2,
    A B两个线程只有拿到两把锁才能完成任务。
    而A线程拿到O1对象锁,然后在锁池中找o2对象锁。然后就一直找啊找。
    而B线程已经在所池中找到了o2对象锁,线程B在锁池中一直找O1对象锁。
    这个时候,程序没有异常,这回永无止境的执行。成为死锁。

    活锁:原因都是太谦让了。在一个三叉路口ABC三条路,其中有AB两条路各有一辆车,但都想去第三条路C,
    A然B先走,B让A先走。一直的谦让下去。程序没有执行。并且永无止境的执行。称为活锁。

产生死锁的4个条件:
资源互斥条件:一把对象锁只能被一个线程占用。
请求与保持条件:我拿着这一把锁,再去找另一把锁。
不剥夺条件:一个线程拿到了资源,但没使用完,就一直不放手。
循环等待条件:没找到对象锁就一直等;

怎么避免死锁:
1、尽量不适用Synchronized进行嵌套使用。
2、都每个锁都是用时间的限制。如果某个线程持有的对象的时间到了,就立即释放锁。
3、对获得锁的顺序进行限制。按顺序获得锁,只要拿到A对象锁,才能拿到b对象锁。这样就直避免死锁。

自旋锁

    在Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,
    这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。


可重入锁

    reentrantlock
    对于同一个线程在外层方法获取锁的时候,在进入内层方法时也会自动获取锁。
    优点可以在一定程度上避免死锁。

独享锁和共享锁

两种锁只是一种概念
独享锁:该锁一次只能被一个线程所持有

共享锁:该锁可以被多个线程所持有

举例:

synchronized是独享锁;

可重入锁ReentrantLock是独享锁;

读写锁ReentrantReadWriteLock中的读锁ReadLock是共享锁,写锁WriteLock是独享锁。

独享锁与共享锁通过AQS(AbstractQueuedSynchronizer)来实现的,通过实现不同的方法,来实现独享或者共享。

互斥锁和读写锁

    互斥锁的具体实现就是synchronized、ReentrantLock。ReentrantLock是JDK1.5的新特性,
    采用ReentrantLock可以完全替代替换synchronized传统的锁机制,更加灵活。

    读写锁的具体实现就是读写锁ReadWriteLock。

锁池

假如线程A拿到了对象锁开始执行程序,那么线程B、线程C、线程D 也想这行被Synchronized修饰的代码、但是对象锁
被线程A拿着,但是A线程还在占着对象锁,那么这个时候,线程BCD就会在一个地方等待A线程释放这把对象锁。
这个等待的地方就是锁池。
等待区:
    我们知道生产者在消费者中。在处于某个对象上活动的线程。当这个对象调用了wait方法的时候,
    处于在这个的对象上的线程,会立即释放占有的对象锁。并且该线程会不会直接进入锁池,会进入
    等待区,等待该线程被唤醒,当这个对象调用notify和notifyAll方法的时候。该线程会进入锁池
    继续寻找对象锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值