java浅谈锁

    当使用synchronized关键字时,实际上是获得了当前对象上的锁。在Java中,每一个对象都有与之关联的锁。这个关键字可以用到任意的代码块中。例如,将一段代码包含到synchronized块中,就可以在这段代码中提供原子操作,如下所示:

      synchronized (this){
                //program statements;

    }

同步语句获得了由this关键字制定的当前对象上的锁,并且为原子操作来执行包含在花括号中的所有程序语句。this仅仅是指向当前对象的引用,此外,还可以使用指向其他对象的引用,程序将获得制定对象上的锁。(在获得线程执行块的整个期间,将会锁定整个对象。因此,为了调用这个对象的其他方法,其他任何的线程都不得不等待)

     调用synchronized方法的顺序不当,可能造成死锁,不恰当或者过度的同步还会导致应用程序的效率的降低

      比喻:

            有两个运行在不同处理器上的线程,两者都可以访问某个通用变量,很明显,这个变量存在于机器的通用主存中,两个处理器都可能缓存这个变量。因此,在没有同步的情况下,从处理器各自的缓存中读取,对于同一个通用变量,这两个线程可能看见不同的值。当对监视器同步时,在获得锁之后,Java内存模型(Java Memory Model,JMM)要求缓存立即消失,然后在释放之前刷新缓存,频繁的刷新缓存可能很耗费资源,这就解释了使用同步时的性能损失问题。

      即使当程序中只包含运行在单个处理器的单个线程上时候,同步方法的调用也要比非同步方法的调用耗费更多的时间。如果同步需要竞争锁,那么很大程度上提高性能的损失。这是因为在获得锁之前,系统中可能发生若干个线程切换和系统调用。

     最佳选择方法:多线程程序需要足够的同步以便保护共享数据,避免他们受到破坏,但不要过分同步,进而避免死锁或者性能上的下降,需要在两者之间平衡,使用volatile关键字的结果是以更高效的方法实现同步。

private int sharedVariable;
	
	public synchronized int getSharedVariable(){
		return sharedVariable;
	}
	
	public synchronized void setSharedVariable(int sharedVariable){
		this.sharedVariable=sharedVariable;
	}
下面的代码给出更好的方式:

private volatile int sharedVariable;
	
	public  int getSharedVariable(){
		return sharedVariable;
	}
	
	public  void setSharedVariable(int sharedVariable){
		this.sharedVariable=sharedVariable;
	}
现在,我们将变量标记为volatile,而不是将访问方法设置为synchronized,这样做更高效, 因为volatile只是在线程和内存之间同步变量的值,而同步方法除了要锁定和释放监视器外,还要为线程的所有变量在线程和主存之间提供同步。

死锁:当两个或者多个线程竞争以获得某个共享资源的锁时,没有线程能够继续执行,除非其他的线程将自己的持有的锁释放。死锁发生后,所有的竞争线程都不能继续。

死锁的解决办法;

     1.锁的顺序

     2. 锁超时,

     3. 死锁检测

1锁的顺序:如果所有的线程都以同样的顺序来或者和释放多个对象的锁,那么死锁就不会发生。一般规则是:存在多个锁的情况下,如果任意线程总是按照相同顺序来获得所有的锁,死锁就不可能发生,但是,并不是总是能够在获得任何锁之前都知道所需要的锁。

2锁超时:在给定的超时期限内,如果线程没有成功的获得所必须的锁,线程将回退,释放目前所有获得的锁,然后在等待随机 的时间内尝试再次获得锁。这种随机的等待时间给了其他的线程获得锁的公平机会。

          

Lock lock=new ReentrantLock();
	lock.lock();
	lock.unlock();
可以使用tryLock(long timeout,TimeUnit timeUnit)方法来指定试图获取某个锁的超时时间,包含在lock(),unlock()之间的语句代码会作为原子操作执行,并且从不损坏系统的完整性

3 死锁检测:首先记录所有的线程的每一个请求和获得每一个锁,通常情况下,为了方便遍历,他们被存储在映射或者视图中,当对锁的请求被拒绝后,线程会遍历这个锁图来检查死锁。 

      解决办法:1 释放所有的锁并且撤回所有等待的请求,然后在每一个线程试图获取所期望的锁之前等待某个随机访问。这无法保证重新获得锁的第二次尝试会成功,并且我们可能需要重复整个过程若干次,尤其当被调用的线程的数目非常大的时候。

                       2 进行基于优先级的回退,只是回退几个被分配了较低优先级的线程,而其他的线程继续持有他们的锁。当检测到死锁时,这些回退的线程自身的优先级可能是随机分配的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值