多线程续

volatile与synchronized比较

volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,volatile只能修饰变量,而synchronized可以修饰方法,代码块,但是它就具备可见性,不具备原子性

CAS

是由硬件实现的,CAS可以将read-modify-write这类操作转化为原子操作

i++自增操作包括三个操作

从主内存读取i变量值

对i的值加1

再把加1之后的值保存到主内存

CAS原理在把数据更新到主内存时,再读取主内存变量的值,如果现在变量的值与期望的值(操作起始时读取的值)一样就更新

public class  Test{
    public static void main(String[] args) {
        TwoTest twoTest=new TwoTest();
        for (int i=0;i<100;i++){
            //System.out.println(twoTest.incrementAndGet()+"----------"+Thread.currentThread().getName());
           new Thread(){
               @Override
               public void run() {
                   System.out.println(twoTest.incrementAndGet()+"----------"+Thread.currentThread().getName());
               }
           }.start();
        }
    }
}

class TwoTest {
    volatile private long value;

    public  long getValue(){
        return  value;
    }

    private  boolean compareAndSwap(long expectedValue,long newValue){
        synchronized (this){
            if(value==expectedValue){
                value=newValue;
                return true;
            }else {
                return  false;
            }
        }
    }

    public long incrementAndGet(){
        long oldvalue;
        long newvalue;
        do {
            oldvalue=value;
            newvalue=oldvalue+1;
        }while (!compareAndSwap(oldvalue,newvalue));
        return newvalue;
    }
}

CAS实现原子操作背后有一个假设,共享变量的当前值与当前线程提供的期望值相同,就认为这个变量没有被其他线程修改过

实际上这种假设不一定总是成立如共享变量count=0

A线程修改其为10

B线程修改其为20

C线程修改为0

这就是CAS中的ABA问题即共享变量经历ABA的更新

这跟算法有关

如果想要规避ABA问题,可以为共享变量引入一个修订号(时间戳)

原始变量类

原子变量类基于CAS实现的,对共享变量进行读写更新操作时,通过原子变量类可以保障操作的原子性与可见性,对变量的读写更新操作是指当前操作不是一个简单赋值,而是变量的新值,依赖变量的旧值,如自增操作i++,由于volatile只能保证可见性,不能保障原子性,原子变量类内部就是一个volatile变量,并且保障了该变量的读写操作的原子性,有时把原子类看作增强的volatile变量,有12个如:

分组原子变量类
基础数据型AtomicInteger,AtomicLong,AtomicBoolean
数组型AtomicIntegerArray,atomiclongarray,atomicreferencearray
字段更新器atomicintegerfieldupdater,atomiclongfieldupdater,atomicreferencefieldupdater
引用型atomicreference,atomicstampedreference,atomicmarkablereference

atomicintegerfieldupdater

atomicintegerfieldupdater可以对原子整数字段进行更新,要求:

字符必须使用volatile修饰,使线程之间可见

只能是实例变量,不能是静态变量,也不用使用final修饰

线程间的通讯

等待/通知机制

什么是通知机制

在单线程编程中,要执行的操作要满足一定的条件才能执行,可以把这个操作放在if语句块中

在多线程编程中,可能A线程的条件没有满足只是暂停,稍后其他线程B可能会更新条件使得A线程的条件得到满足,可以将A线程暂停,直到它得到条件后才被唤醒

等待/通知机制的实现

object类中的wait()方法使执行当前代码的线程等待,执行执行直到通知或被中断为止

注意:

wait()方法只能在同步代码中由锁对象调用

调用wait方法,当前线程会释放锁

Object类的notify()可以唤醒线程,这个也必须在同步代码中由锁对象调用,没有使用锁对象调用wait()/nofify会抛出异常,如果有多个等待的线程,方法只会随机唤醒一个,在调用方法后并不会立即释放锁对象,需要当前同步代码块执行完后才会释放锁对象,一般将notify方法放在同步代码块的最后

notify方法被调用不会立即执行

interrupt()方法中断wait()

当线程处于wait等待状态时,调用线程对象的interrupt方法会中断线程的等待状态

notify()和notifyall()

前者一次只能唤醒一个线程,还是随机唤醒的,要唤醒所有线程使用后者

public class TenTest {

    static String a;
    public static void main(String[] args) {
        a="123";
        new Thread(new Runnable() {
            @Override
            public void run() {

                synchronized (a){
                    try {
                        System.out.println("关闭");
                        a.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("开启");
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (a){
                    try {
                        System.out.println("关闭");
                        a.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("开启");
                }
            }

        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (a){
                    try {
                        System.out.println("关闭");
                        a.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("开启");
                }
            }
        }).start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i=0;i<50;i++){
            System.out.println(i);
            if(i==25){
                synchronized (a){
                    a.notifyAll();
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值