专栏首页技术圈Java 同步 synchronized与lock

Java 同步 synchronized与lock

实现线程同步一个使synchronized关键字,一个是通过对象lock. Lock 在jdk 1.5才出现的,在一定程度上缓解了synchronized同步所带来的性能下降。

Synchronized

synchronized时对象一定会被阻塞,其他线程必须等待锁释放后才能执行,在高并发的情况下,很容易降低性能,而且不容易控制会出现死锁。 原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低。

Lock

需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。 lockk用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就是CAS操作(Compare and Swap).

public class LockTest {  
    public static void main(String[] args) {  
        final Outputter1 output = new Outputter1();  
        new Thread() {  
            public void run() {  
                output.output("zhangsan");  
            };  
        }.start();        
        new Thread() {  
            public void run() {  
                output.output("lisi");  
            };  
        }.start();  
    }  
}  
class Outputter1 {  
    private Lock lock = new ReentrantLock();// 锁对象  
    public void output(String name) {  
        // TODO 线程输出方法  
        lock.lock();// 得到锁  
        try {  
            for(int i = 0; i < name.length(); i++) {  
                System.out.print(name.charAt(i));  
            }  
        } finally {  
            lock.unlock();// 释放锁  
        }  
    }  
}  

Synchronized 和Lock

synchronized 要比lock同步的性能消耗高,而lock比synchronized优越就优越在的java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,这样就可以基于lock实现不同的调用算法、性能特性或者锁定语义。 我们之前说synchronized在多线程竞争激烈的时候可能会出现性能极速下降的问题。ReentrantLock在多线程抢占资源的时候可以保障当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。 利用ReentrantLock()来保护共享资源。

Lock lock = new ReentrantLock();  
lock.lock();  
try {   
  // update object state  
}  
finally {  
  lock.unlock();   
}  

ReentrantLock获得锁的方式

lock(),如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,知道获取锁 trylock(),如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false trylock(),如果获取了锁立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待过程如果获得了锁,则返回true,如果等待超时,则返回false。 lockInterruptibly,如果截取了锁则立即返回,如果没有获取锁定,当前线程处于休眠状态,直到获得锁,或者是当前线程被别的线程中断。 我们看出使用ReentrantLock来实现同步相对于Synchronized更灵活, 一方面 在Synchronized中使用同步可能会出现等待持有对象锁的线程释放锁,但是如果这个线程的周期很长,在这个过程中等待中的线程可能会一直等待直到等死。这样就消耗了大量了系统资源。 另一方面出现死锁的可能性更大,线程A拿到锁,并且runing,而线程B等待A释放锁,如果A需要B中的资源,就陷入了无限等待的过程中了。 最后,在多线程共享资源时,减少了线程间切换所花费得资源,对CPU的利用率比较低。 ReentrantLock给了一种机制让我们来响应中断,可能自行中断,也可以被线性中断,是很灵活的。 应用场景: lock支持的时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票。 synchronized可以实现的功能,基本上lock都能实现。虽然看起来lock的出现似乎已经可以取代synchronized,但是synchronized似乎也有些优点,lock中的锁定类是用于高级用户和高级情况的工具,如果在没有特别的需求的情况下一般还是以使用synchronized为主,另外,lock需要程序员手动加锁和手动释放锁,而synchronized在退出 synchronized 块时JVM就能自动的释放锁。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java多线程--线程各状态如何进行切换

    1、新建状态(New):新创建了一个线程对象。 2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于...

    张凝可
  • JAVA中常见的API比较

    clone(),equals(),hasCode(),notify(),notifyAll(),toString(), finalize(),wait()

    张凝可
  • Java 多线程---基本概念

    ** 进程本质是执行中的程序。 线程是程序中流控制。本身是不能执行的,只能使用分配给程序的资源。 进程-线程 一个进程可以包含一个或者多个线程,...

    张凝可
  • ThreadLocal (下) 继承性

    通过以上例子可以看到,同一个ThreadLocal变量在父线程中设置值后,在子线程是取不到的。根据上节的介绍,这应该是正常现象。因为子线程thread里面调用g...

    YanL
  • ThreadLocal (下) 继承性问题解决,以及具体实现原理

    通过以上例子可以看到,同一个ThreadLocal变量在父线程中设置值后,在子线程是取不到的。根据上节的介绍,这应该是正常现象。因为子线程thread里面调用g...

    YanL
  • Java并发学习2【面试+工作】

      关键字synchronized的作用是实现进程间的同步。它的工作是对同步的代码加锁,使得每一次,只能有一个线程进入同步块,从而保证线程间的安全性(即同步块每...

    Java帮帮
  • 《实战Java高并发程序设计》读书笔记

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

    大黄大黄大黄
  • wait()方法和notify()方法使用时的注意事项

    我们看程序出线了异常。原因是我们没有添加synchronized关键字,所以线程获取不到锁,而直接抛出的异常。

    吉林乌拉
  • Java并发编程的艺术(七)——Executors

    Executors框架简介 Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架...

    大闲人柴毛毛
  • Java的wait和notify学习三部曲之一:JVM源码分析

    Java的wait()、notify()学习三部曲由三篇文章组成,内容分别是:一、通过阅读openjdk8的源码,分析和理解wait,notify在JVM中的具...

    程序员欣宸

扫码关注云+社区

领取腾讯云代金券