1、原子引用

package com.example.mybaties;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

import java.util.concurrent.atomic.AtomicReference;

/**
 * @DESCRIPTION 原子引用
 * @Author lst
 * @Date 2020-03-24 09:00
 */
public class AtomicReferenceDemo {


    public static void main(String[] args) {
        User z3 = new User("z3",22);
        User li4 = new User("li4",25);

        AtomicReference<User> atomicReference = new AtomicReference();

        atomicReference.set(z3);
        System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());
        System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());//主物理内存已经变成li4
        /**
         * true	 User(userName=li4, age=25)
         * false	 User(userName=li4, age=25)
         */


    }
}

@Getter
@ToString
@AllArgsConstructor
class User {

    String userName;

    int age;

}

2、可重入锁

package com.example.mybaties;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @DESCRIPTION 可重入锁(也叫递归锁)
 * 指的是同一线程外层脳数获得锁之后,内层递归数仍然能获取该锁的代吗,在同一个线程在外层方法英取的时候,
 * 在进入内层方法会自动获取锁也即是说,线程可以进入一个任何它已经拥有的所同歩的代码块
 *
 *
 *   就是一个典型的可重入锁
 *
 * 11invoked sendSms
 * 11#######invoked sendEmail
 * 12invoked sendSms
 * 12#######invoked sendEmail
 *
 *
 *
 * @Author lst
 * @Date 2020-03-23 14:48
 */

class Phone implements  Runnable{

    public synchronized void sendSms(){
        System.out.println(Thread.currentThread().getId() + "invoked sendSms ");
        sendEmail();
    }

    public synchronized void sendEmail(){
        System.out.println(Thread.currentThread().getId() + "#######invoked sendEmail ");
    }


    Lock lock = new ReentrantLock();//默认非公平锁


    @Override
    public void run() {
        get();
    }

    public void get(){
        lock.lock();
        lock.lock();

        System.out.println(Thread.currentThread().getName() + "  invoked get() ");
        set();

        lock.unlock();
        lock.unlock();

    }

    public void set(){
        lock.lock();

        System.out.println(Thread.currentThread().getName() + "  ####invoked set() ");
        lock.unlock();
    }
}


public class ReenterLockDemo {

    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> {
            phone.sendSms();
        },"t1").start();

        new Thread(() -> {
            phone.sendSms();
        },"t2").start();

        //暂停一会
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println();

        Thread t3 = new Thread(phone,"t3");
        Thread t4 = new Thread(phone,"t4");
        t3.start();
        t4.start();

        /**
         * 14invoked sendSms
         * 14#######invoked sendEmail
         * 13invoked sendSms
         * 13#######invoked sendEmail
         *
         *
         *
         *
         *
         * t3  invoked get()
         * t3  ####invoked set()
         * t4  invoked get()
         * t4  ####invoked set()
         */
    }

}

3、读写锁

/**
 * @DESCRIPTION 读写锁
 *多个线程同时读一个资源关没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行
 * 但是如果有一个线程想去写共享资源来,就不应该再有其它线程可以对该资源进行读或写
 * 小总结
 *      读-读能共存
 *      读-写不能共存
 *      写不能共存
 *
 *
 *      写操作:原子(完整一致性)+独占,整个过程必须是一个完整的统一体,中间不能间断
 *
 * @Author lst
 * @Date 2020-03-24 12:00
 */

class MyCache {  //资源类

    private volatile Map<String,Object> map = new HashMap<>();
    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void put(String key,Object value){
        //写锁
        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"  正在写入: " +key);
            //暂停一会线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"  写入完成: " );
        }catch (Exception e){
            e.getMessage();
        }finally {
            rwLock.writeLock().unlock();
        }
    }

    public void get(String key){
        //读锁
        rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"  正在读取: " +key);
            //暂停一会线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Object result =  map.get(key);
            System.out.println(Thread.currentThread().getName()+"  读取完成: " + result);
        }catch (Exception e){
            e.getMessage();
        }finally {
            rwLock.readLock().unlock();
        }
    }

    public void clearMap(){
        map.clear();
    }


}

public class ReentranRreadWriteLockDemo {

    public static void main(String[] args) {
        MyCache myCache = new MyCache();

        for (int i = 0; i < 5; i++) {
            final String keyValue = String.valueOf(i);
            new Thread(() -> {
                myCache.put(keyValue,keyValue);
            },keyValue).start();
        }



        for (int i = 0; i < 5; i++) {
            final String keyValue = String.valueOf(i);
            new Thread(() -> {
                myCache.get(keyValue);
            },keyValue).start();
        }


     /* 0  正在写入: 0
        0  写入完成:
        1  正在写入: 1
        1  写入完成:
        2  正在写入: 2
        2  写入完成:
        3  正在写入: 3
        3  写入完成:
        4  正在写入: 4
        4  写入完成:
        0  正在读取: 0
        1  正在读取: 1
        2  正在读取: 2
        3  正在读取: 3
        4  正在读取: 4
        0  读取完成: 0
        1  读取完成: 1
        2  读取完成: 2
        3  读取完成: 3
        4  读取完成: 4
        */


     ShareResource shareResource = new ShareResource();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print5();
            }
        },"A").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print10();
            }
        },"B").start();


        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print15();
            }
        },"C").start();

    }

}

4、synchronized和lock有什么区别?用新的lock有什么好处?你挙例说说

/**
 * 题目: synchronized 和lock有什么区别?用新的lock有什么好处?你挙例说说
 * 1、原始构成
 *      synchronized是关字jvm层面,
 *          monitorenter(底层是通过monitor对象来完成,其实wait/ notify等方法也依 monitor对象只有在同步块或方法中能源ait/ notify等方
 *          monitorexit
 *      Lock是具体类(java,utiL, concurrent. Locks.Lock)是api层面的锁
 * 2、使用方法
 *      synchronized 不需要用户去手动释放锁,当 synchronized代码执行完后系统会自动让线程释放对锁的占用
 *      Reentrantlock则需要户去手动释放锁,若没有主动释放锁,就有可能导致出现死锁现象。需要Lock()和unLock()方法配合try/ finally语句块来完成
 * 3、等待是否可中断
 *      synchronized 不可中断,除非抛出异常或者正常运行完成
 *      Reentrantlock 可中断,
 *                  1.设置超时方法 trylock( long timeout, Timeunit unit)
 *                  2. LockInterruptibly()放代码块中,调 interrupt()方法可中断
 * 4、加锁是否公平
 *      synchronized非公平锁
 *      Reentrantlock 两者都可以,默认非公平锁,构造方法可以传入 boolean值,true为公平锁, false为非公平锁
 *
 * 5、锁绑定多个条件 Condition
 *      synchronized没有
 *      Reentrantlock,用来实分组唤要唤的线程,可以精确唤醒,而不是像 synchronized要么随机唤醒一个线程 要么唤醒全部线程
 *
 *
 * 原始构成:synchronized是JVM层面的,底层通过monitorenter和monitorexit来实现的。Lock是JDK API层面的。(synchronized一个enter会有两个exit,一个是正常退出,一个是异常退出(保证肯定可以退出))
 * 使用方法:synchronized不需要手动释放锁,而Lock需要手动释放。
 * 是否可中断:synchronized不可中断,除非抛出异常或者正常运行完成。Lock是可中断的,1.设置超时方法tryLock(long timeout,TimeUnit unit); 2. lockInterruptibly()方法放代码块中,调用interrupt()
 * 是否为公平锁:synchronized只能是非公平锁,而ReentrantLock既能是公平锁,又能是非公平锁,构造方法传入false/true,默认是非公平锁false。
 * 绑定多个条件:synchronized不能,只能随机唤醒。而Lock可以通过Condition来绑定多个条件,精确唤醒。
 *
 *
 * 题目:多线程之按顺序调用,实现A->B->C三个线程启动,要求如下
 * AA打印5次,BB打印10次,CC打印15次
 * 紧接着
 * AA打印5次,BB打印10次,CC打印15次
 * 。。。。。。
 * 来10轮
 *
 */

class ShareResource{
    private int number = 1;//A:1   B:2    C:3
    private Lock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();

    public void print5(){
        lock.lock();

        try{

            //1、判断
            while (number != 1){
                c1.await();
            }

            //2、干活
            for (int i = 1; i <= 5 ; i++) {
                System.out.println(Thread.currentThread().getName()+"   " + i);
            }

            //3、通知
            number = 2;
            c2.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void print10(){
        lock.lock();
        try{

            //1、判断
            while (number != 2){
                c2.await();
            }

            //2、干活
            for (int i = 1; i <= 10 ; i++) {
                System.out.println(Thread.currentThread().getName()+"   " + i);
            }

            //3、通知
            number = 3;
            c3.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void print15(){
        lock.lock();

        try{

            //1、判断
            while (number != 3){
                c3.await();
            }

            //2、干活
            for (int i = 1; i <= 15 ; i++) {
                System.out.println(Thread.currentThread().getName()+"   " + i);
            }

            //3、通知
            number = 1;
            c3.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }