Volatile和锁Synchronized,cas(Atomic),ReentrantLock,ReadWriteLock 笔记

Volatile

         特点: 1 线程可见性 2 禁止指令重排序 3但是不保证原子性操作

Synchronized 锁

特性:

原子性 ,可见性,可重入锁,异常会释放锁,非公平锁

使用:

1 加在方法上,如果是非静态方法就是锁住了这个对象,这个对象多个Synchronized方法只能执行一个

2 加在方法上,如果是静态方法就是锁住了这个类,这个类多个Synchronized方法只能执行一个

3 加在对象上,Synchronized 对象同样的代码段只能执行一个

4 加在class上,Synchronized 同样的类代码段只能执行一个

锁升级:

偏向锁-》自旋锁-》重量锁

偏向锁:一个线程的时候记录这个线程,下次默认锁就是他的

自旋锁:多于一个线程,就会转换成自旋锁,默认自旋10次进入队列

重量锁:进入cpu队列不耗费cpu资源

自旋锁 什么时候用?执行时间短,线程少

系统锁  什么时候用?执行时间长,线程多

其他:

Synchronized 锁优化:

1 锁细化锁的代码越少越好

2 锁粗化,合并多个小锁

不能当为锁的对象:

String,Integer,Character、Short、Long因为有缓存,会导致对象改变问题(基础类型int啥的也不行)

死锁的例子:

https://www.cnblogs.com/pweizhao/articles/9066728.html

 

Cas(无锁优化 自旋)compare and set  比较 设定

AtomicInteger 线程安全的integer 好多Atomic开口的类都是线程安全的

用 increamnet添加数

这些类保证线程安全用的是Cas(要改的值V,期望值Expected,改后的值NewValue) CPU指令级别中间不会被打断

Unsafe 类 直接操作java虚拟机内存

基于CAS实现的类java.util.concurrent.atomic

ABA问题

1 如果有3个线程   分别是 +1 -1 +1的操作 从结果来说是没区别的

2 但是对象类型的就不行,是有区别的,要加版本号解决这个问题

LongAdder,AtomicLong,Synchronized 三个关于累加的对比

例子

static long count2 = 0L;
    static AtomicLong count1 = new AtomicLong(0L);
    static LongAdder count3 = new LongAdder();

    public static void main(String[] args) throws Exception {
        Thread[] threads = new Thread[1000];

        for(int i=0; i<threads.length; i++) {
            threads[i] =
                    new Thread(()-> {
                        for(int k=0; k<100000; k++) count1.incrementAndGet();
                    });
        }

        long start = System.currentTimeMillis();

        for(Thread t : threads ) t.start();

        for (Thread t : threads) t.join();

        long end = System.currentTimeMillis();

        //TimeUnit.SECONDS.sleep(10);

        System.out.println("Atomic: " + count1.get() + " time " + (end-start));
        //-----------------------------------------------------------
        Object lock = new Object();

        for(int i=0; i<threads.length; i++) {
            threads[i] =
                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        for (int k = 0; k < 100000; k++)
                            synchronized (lock) {
                                count2++;
                            }
                    }
                });
        }

        start = System.currentTimeMillis();

        for(Thread t : threads ) t.start();

        for (Thread t : threads) t.join();

        end = System.currentTimeMillis();


        System.out.println("Sync: " + count2 + " time " + (end-start));


        //----------------------------------
        for(int i=0; i<threads.length; i++) {
            threads[i] =
                    new Thread(()-> {
                        for(int k=0; k<100000; k++) count3.increment();
                    });
        }

        start = System.currentTimeMillis();

        for(Thread t : threads ) t.start();

        for (Thread t : threads) t.join();

        end = System.currentTimeMillis();

        //TimeUnit.SECONDS.sleep(10);

        System.out.println("LongAdder: " + count1.longValue() + " time " + (end-start));

    }

输出

Atomic: 100000000 time 1523
Sync: 100000000 time 3819
LongAdder: 100000000 time 454

结论

Atomic   用的cas所以快于Sync

LongAdder 用的分段锁+cas ,线程越多比Atomic越快,线程少Atomic快

Lock锁的实现

1 ReentrantLock

使用  Lock lock= new ReentrantLock   加锁Lock.lock 解锁Lock.unlock 

比snchronized的好处

1 trylock 可以申请几秒之内得到一把锁

2 lockinterruptibly 

3 公平锁排队取锁

例子:

//private static ReentrantLock lock=new ReentrantLock(true); //参数为true表示为公平锁,请对比输出结果
	public static void main(String[] args) {
		Lock lock = new ReentrantLock();



		Thread t1 = new Thread(()->{
			try {
				lock.lock();
				System.out.println("t1 start");
				TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
				System.out.println("t1 end");
			} catch (InterruptedException e) {
				System.out.println("interrupted!");
			} finally {
				lock.unlock();
			}
		});
		t1.start();
		
		Thread t2 = new Thread(()->{
			try {
				//lock.lock();
				lock.lockInterruptibly(); //可以对interrupt()方法做出响应
				System.out.println("t2 start");
				TimeUnit.SECONDS.sleep(5);
				System.out.println("t2 end");
			} catch (InterruptedException e) {
				System.out.println("interrupted!");
			} finally {
				lock.unlock();
			}
		});
		t2.start();
		
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.interrupt(); //打断线程2的等待
		
	}

2 ReadWriteLock

读锁  可以有多个读锁与写锁互斥

写锁 只能有一个写锁

例子:

static Lock lock = new ReentrantLock();
    private static int value;

    static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    static Lock readLock = readWriteLock.readLock();
    static Lock writeLock = readWriteLock.writeLock();

    public static void read(Lock lock) {
        try {
            lock.lock();
            Thread.sleep(1000);
            System.out.println("read over!");
            //模拟读取操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void write(Lock lock, int v) {
        try {
            lock.lock();
            Thread.sleep(1000);
            value = v;
            System.out.println("write over!");
            //模拟写操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }





    public static void main(String[] args) {
        //Runnable readR = ()-> read(lock);
        Runnable readR = ()-> read(readLock);

        //Runnable writeR = ()->write(lock, new Random().nextInt());
        Runnable writeR = ()->write(writeLock, new Random().nextInt());

        for(int i=0; i<18; i++) new Thread(readR).start();
        for(int i=0; i<2; i++) new Thread(writeR).start();


    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值