多线程与高并发学习二

Volatile不能保证原子性

public class VolatileNotSync {
    volatile int count = 0;

    void m() {
        for (int i = 0; i < 10000; i++) count++;
    }

    public static void main(String[] args) {
        T04_VolatileNotSync t = new T04_VolatileNotSync();

        List<Thread> threads = new ArrayList<Thread>();

        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(t::m, "thread-" + i));
        }

        threads.forEach((o) -> o.start());

        threads.forEach((o) -> {
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t.count);


    }

}

输出结果如下(如果能保证原子性的话则应输出100000):
在这里插入图片描述

锁的细化DEMO


public class FineCoarseLock {

    int count = 0;

    synchronized void m1() {
        //do sth need not sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //业务逻辑中只有下面这句需要sync,这时不应该给整个方法上锁
        count++;

        //do sth need not sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    void m2() {
        //do sth need not sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //业务逻辑中只有下面这句需要sync,这时不应该给整个方法上锁
        //采用细粒度的锁,可以使线程争用时间变短,从而提高效率
        synchronized (this) {
            count++;
        }
        //do sth need not sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


}

应该避免锁定对象的引用变成另外的对象

锁定某个对象o,如果o的属性发生改变,不影响锁的使用,但是如果o变成另外一个对象,则锁定的对象发生改变,因为对象做锁的时候,它的锁的标记位在markword上面,如果锁的对象发生改变,则它的markword标记也发生改变了,就会导致程序出现问题
代码如下:


public class SyncSameObject {

    /*final*/ Object o = new Object();

    void m() {
        synchronized (o) {
            while (true) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());


            }
        }
    }

    public static void main(String[] args) {
       SyncSameObject t = new SyncSameObject();

        new Thread(t::m, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Thread t2 = new Thread(t::m, "t2");

        t.o = new Object(); //锁对象发生改变,所以t2线程得以执行,如果注释掉这句话,线程2将永远得不到执行机会
        t2.start();

    }
}

CAS的ABA问题理解

如果是基础类型,ABA问题无所谓,如果是引用类型就需要去解决了
ABA问题解决方式:加Version版本号控制,采用AtomicStampedReference。
ABA问题造成的后果: 假设有 A、B、C这三个对象,A这个对象指向B,B又指向C调用C的逻辑,如果采用CAS的方式,先让A指向C,然后对C对象里面的业务逻辑做一些更改,再让A重新指向B,然后另一个线程再直接通过A调用B然后再调用C,可能里面的执行结果,就受上一个线程的执行结果所干扰了。
其中AutomicInteger的incrementAndGet() 方法最终调用了Unsafe类的compareAndSwapInt方法
Unsafe类的JDK8版本实现:
直接操作内存

  • allocateMemory putXX freeMemory pageSize
    直接生成类实例
  • allocateInstance
    直接操作类或实例变量
    -objectFieldOffset
    -getInt
    -getObject
    CAS相关操作
    -compareAndSwapObject Int Long
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值