Android 价值千万java多线程同步 <四> synchronized&Lock&Atomic6种方式

 

1).Android 价值千万   java线程专题:Wait&notify&join&Yield

http://blog.csdn.net/whb20081815/article/details/65627387

2).Android 价值千万    java多线程同步 <二>Callable和Future&FutureTask

http://blog.csdn.net/whb20081815/article/details/65630694

3).Android 价值千万    java多线程<三>生产者消费者模型四种实现方法

http://blog.csdn.net/whb20081815/article/details/65635647

 4).Android 价值千万    java多线程同步 <四> synchronized&Lock&Atomic6种方式

http://blog.csdn.net/whb20081815/article/details/66971983

 

5).Android 价值千万java多线程同步 <五>CountDownLatch(计数器)和Semaphore(信号量)

http://blog.csdn.net/whb20081815/article/details/68498371

6).Android AsyncTask 那些你不知道的事

https://blog.csdn.net/WHB20081815/article/details/70332209

7).Android 厉害了ThreadLocal的工作原理和实例分析

https://blog.csdn.net/WHB20081815/article/details/66974651

8).Android Handle消息机制:秒懂Looper、Handler、Message三者关系

https://blog.csdn.net/WHB20081815/article/details/67639060

9).Android 性能优化<八> 多线程优化和线程管理

https://blog.csdn.net/WHB20081815/article/details/77775444

 

 

多线程同步的六种方式,主要以前3项为主!

一、synchronized

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

当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块.

 

public void run() {
    // 获取锁
    // 执行现金业务
    synchronized (UserSynch.this){
        System.out.println("UserSynch"+name + "正在操作" + myCount + "账户,金额为" + iocash
                + ",当前金额为" + myCount.getCash());
        myCount.setCash(myCount.getCash() + iocash);
        System.out.println(name + "操作" + myCount + "账户成功,金额为" + iocash
                + ",当前金额为" + myCount.getCash());
    }
}

二:使用重入锁实现线程同步

   ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。

public void run() {
    // 获取锁
    myLock.lock();
    // 执行现金业务
    System.out.println(name + "正在操作" + myCount + "账户,金额为" + iocash
            + ",当前金额为" + myCount.getCash());
    myCount.setCash(myCount.getCash() + iocash);
    System.out.println(name + "操作" + myCount + "账户成功,金额为" + iocash
            + ",当前金额为" + myCount.getCash());
    // 释放锁,否则别的线程没有机会执行了
    myLock.unlock();
}

Lock接口以及对象,使用它,很优雅的控制了竞争资源的安全访问,但是这种锁不区分读写,称这种锁为普通锁。为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在一定程度上提高了程序的执行效率。

//创建一个锁对象
ReadWriteLock lock = new ReentrantReadWriteLock(false);

 

Condition

ConditionObject监视器方法(waitnotify notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待 setwait-set)。

Lock

Lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。

ReadWriteLock

ReadWriteLock维护了一对相关的锁定,一个用于只读操作,另一个用于写入操作。

 

  注:关于Lock对象和synchronized关键字的选择: 

        a.最好两个都不用,使用一种java.util.concurrent包提供的机制,能够帮助用户处理所有与锁相关的代码。 

        b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 

        c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁 

        d.在实际开发中,最好在能用读写锁的情况下使用读写锁,而不要用普通锁,以求更好的性能。

 

三:原子量

private AtomicBoolean mIsOk;

public void run() {
    // 获取锁
    // 执行现金业务
        if(mIsOk.get()){
            mIsOk.set(false);
            System.out.println("UserSynch" + name + "正在操作" + myCount + "账户,金额为" + iocash
                    + ",当前金额为" + myCount.getCash());
            myCount.setCash(myCount.getCash() + iocash);
            System.out.println(name + "操作" + myCount + "账户成功,金额为" + iocash
                    + ",当前金额为" + myCount.getCash());
            mIsOk.set(true);
        }
}

这里要注意的一点是,原子量虽然可以保证单个变量在某一个操作过程的安全,但无法保证你整个代码块,或者整个程序的安全性。因此,通常还应该使用锁等同步机制来控制整个程序的安全性。但是我测试是没有问题的

4.阻塞队列实现线程同步

LinkedBlockingQueue<E>

5.volatile

 

使用场景:

synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。通常来说,使用volatile必须具备以下2个条件:

  1)对变量的写操作不依赖于当前值

  2)该变量没有包含在具有其他变量的不变式中

  实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。

 

对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的

 

代码在单线程中运行是没有任何问题的,但是在多线程中运行就会有问题了。在多核CPU中,每条线程可能运行于不同的CPU中,因此每个线程运行时有自己的高速缓存(对单核CPU来说,其实也会出现这种问题,只不过是以线程调度的形式来分别执行的)。本文我们以多核CPU为例。

volatile这个不常用的关键字原因是这个关键字在高性能的多线程程序中也有很重要的用途,只是这个关键字用不好会出很多问题。

6.ThreadLocal

 

实例:存款和取款

 

public void testLock(){
    // 创建并发访问的账户
    MyCount myCount = new MyCount("95599200901215522", 10000);
    // 创建一个锁对象
    Lock lock = new ReentrantLock();
    // 创建一个线程池
    ExecutorService pool = Executors.newCachedThreadPool();
    // 创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊
    UserLock u1 = new UserLock("张三", myCount, -4000, lock);
    UserLock u2 = new UserLock("张三他爹", myCount, 6000, lock);
    UserLock u3 = new UserLock("张三他弟", myCount, -8000, lock);
    UserLock u4 = new UserLock("张三", myCount, 800, lock);
    // 在线程池中执行各个用户的操作
    pool.execute(u1);
    pool.execute(u2);
    pool.execute(u3);
    pool.execute(u4);
    // 关闭线程池
    pool.shutdown();
}

 

 

AS的demo下载地址:不知道为什么上传不了

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值