美文网首页
线程同步

线程同步

作者: Wu巧不成 | 来源:发表于2017-04-13 15:53 被阅读0次

    什么情况需要用到?
    当多个线程同时操作一个可共享的资源变量时,有可能产生冲突,为了避免这种冲突引入了线程同步的概念。

    作用?
    保证了对共享资源访问的唯一性。

    举个例子:
    我们去食堂吃饭,有一个阿姨负责打饭菜,她同时给几个人打菜,但有时候会给人打错菜,那去吃饭的人就有意见了,于她为了避免这样的问题,于是规定菜饭需要排队,每次只给一个人打菜,这样就比较公平了。
    这个例子是告诉我们,同步就和排队一样,虽然能避免冲突,但也是会影响效率的,但是在某些场合, “公平”却显得更总要一些。

    线程同步有几种方法:
    1.synchronized关键字修饰
    由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

    同步方法
    public synchronized void save(){}
    同步代码块
    synchronized(object){}

    因为同步是一种高开销操作,因此应该尽量减少同步的内容,只同步关键代码就可以。

    2.volatile关键字
    用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,因此每次使用该域就要重新计算,而不是使用寄存器中的值,不能用来修饰final类型的变量。

    例如:private volatile int account = 100; //此变量在做其他操作时即可实现线程同步

    3.重入锁实现线程同步
    JavaSE5.0中新增了一个java.util.concurrent包来支持同步使用的时候new ReentrantLock()对象,调lock()获得锁,关键代码执行完毕后调用unlock()释放锁。

    4.局部变量实现线程同步
    如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

    ThreadLocal() : 创建一个线程本地变量
    get() : 返回此线程局部变量的当前线程副本中的值
    initialValue() : 返回此线程局部变量的当前线程的"初始值"
    set(T value) : 将此线程局部变量的当前线程副本中的值设置为value

    疑问?虽然是有副本,但源头同时被两个人调用,两个都修改了源值,一个先保存了,另一个还未保存的副本修改的内容就没有意义了?

    5.队列实现线程同步
    LinkedBlockingQueue:
    实现了先进先出等特性,队列满的时候会阻塞直到有队列成员被消费,队列空的时候会阻塞,直到有队列成员被放进来。内部对数据的读写采用了锁的机制,和重入锁的概念一致,他的作用是让使用者交替访问共享的资源,避免数据错乱。

    总结一下:
    1.线程同步一定是多个线程访问同一个资源。
    2.只有共享资源的读写访问才需要同步。
    3.只有“变量”才需要同步访问。
    4.使用synchronized关键字同步,应尽量缩小范围。
    5.非线程安全不等于不安全,比如同时访问一个资源,但我每个线程都new一个这个资源对象做操作也不存在安全问题的。

    相关文章

      网友评论

          本文标题:线程同步

          本文链接:https://www.haomeiwen.com/subject/ifbbattx.html