juc学习

作者: 墨宇暗黑 | 来源:发表于2021-12-22 21:26 被阅读0次
学习网站:https://www.bilibili.com/video/BV1B7411L7tE?p=39&spm_id_from=pageDriver

Syncheonized与Lock的区别

1.Syncheonized 是java关键字,Lock是一个java类
2.Syncheonized 无法判断获取锁的状态,Lock可以判断是否获取到了锁
3.Syncheonized 会自动释放锁,Lock必须要手动释放锁,如果不释放会造成死锁
4.Syncheonized 线程1(获得锁阻塞),线程2(会进行等待锁),Lock不一定会等待
5.Syncheonized可重入锁,不可中断的,
6.Syncheonized适合锁少量的代码,Lock适合锁大量的代码

集合类多线程安全问题,使用普通的集合会出现线程安全问题,错误如下:

java.util.ConcurrentModificationException

使用如下办法可以解决:

List<String> list = Collections.synchronizedList(new ArrayList<>());//使用工具类保证线程安全
List<String> list = new CopyOnWriteArrayList<>(); //写入时复制

Callable的使用:

创建一个类实现Callable的类,再创建一个FutureTask(new MyCallable()),最后new Thread(futureTask);注意futureTask只能执行一次

FutureTask task = new FutureTask(new MyCallable());
new Thread(task).start();
class MyCallable implements Callable{String run(){ return "String"; }}

JUC三大常用辅助类CountDownLatch,CycleBarrier,Semaphore

CountDownLatch:里面有一个计数器,每次调用需要手动减一,调用countDownLatch.await()可以当数量为一的时候执行
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(5);//总数是5
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName() + "go out");
                countDownLatch.countDown();//计数减一
            },String.valueOf(i)).start();
        }
        countDownLatch.await();//等待计数器归零,才能乡下执行
        System.out.println("close");
    }
}
Semaphore:共享资源的使用
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3); //线程数量,停车位
        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                try {
                    semaphore.acquire();//获得,加入已经满了,就等待释放
                    System.out.println(Thread.currentThread().getName()+"强盗车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开了车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();//释放,
                }
            },String.valueOf(i)).start();
        }

    }
}

读写锁,读可以多个线程一起读,而写必须一个一个的来,读写也是一样

/*
    独占锁(写锁) 一次只能一个线程占有
    共享锁一次可以被多个线程占有
    读-读 可以共享
    读-写 不能共享
    写-写 不能共享
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        //MyCache myCache = new MyCache(); 不加锁
        MyCacheLock myCache = new MyCacheLock();
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.put(temp + "",temp + "");
            },String.valueOf(i)).start();
        }
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.get(temp + "");
            },String.valueOf(i)).start();
        }
    }
}
class MyCache{ //自定义缓存
    private volatile Map<String,Object> map = new HashMap<>();
    public void put(String key, Object value){
        System.out.println(Thread.currentThread().getName() + "写入" + key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName() + "写入ok");
    }
    public void get(String key){
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取ok");
    }
}
class MyCacheLock{ //自定义缓存
    private volatile Map<String,Object> map = new HashMap<>();
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public void put(String key, Object value){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName() + "写入ok");
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }
    public void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取ok");
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}

阻塞队列,ArrayBlockingQueue,SynchronousQueue

ArrayBlockingQueueapi使用,参考如下
方式 抛出异常 有返回值,不抛出异常 阻塞等待 超市等待
添加 add offer() put() offer(...)
移除 remove poll() take() poll(...)
检查队首元素 element peek()
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        test4();
    }
    public static void test1(){ //抛出异常
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
        //System.out.println(blockingQueue.add("d")); //出国队列大小抛出异常
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove()); //抛出异常,
    }
    public static void test2(){
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        //System.out.println(blockingQueue.offer("c")); //不抛出异常
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.peek());
        //System.out.println(blockingQueue.poll()); //不抛出异常,
    }
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        //blockingQueue.put("d"); 队列没有位置了,一直阻塞
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take()); //没有这个元素,等待元素
    }
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
        blockingQueue.offer("a",3, TimeUnit.SECONDS);
        blockingQueue.offer("b",3, TimeUnit.SECONDS);
        blockingQueue.offer("c",3, TimeUnit.SECONDS);
        // blockingQueue.offer("a",3, TimeUnit.SECONDS); 超时退出
        System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
        System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
        System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
        //System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS)); 超时等待3秒,3秒没有则返回
    }
}
SynchronousQueue:同步队列,存入一个数据,必须把这个数据取出来的时候才能存入下一个数据
public class SynTest { 
    public static void main(String[] args) {
        BlockingQueue blockingQueue = new SynchronousQueue();
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + " put 1");
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName() + " put 2");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName() + " put 3");
                blockingQueue.put("3");
            }catch (Exception e){
                e.printStackTrace();
            }
        },"T1").start();
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "  " + blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "  " + blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "  " + blockingQueue.take());
            }catch (Exception e){
                e.printStackTrace();
            }
        },"T2").start();
    }
}

线程池,三大方法,七大参数,四大拒绝策略。线程池的优点:,节约资源,易于管理

public class Test01 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); //单列线程
        //ExecutorService executorService = Executors.newCachedThreadPool(); //根据情况自动创建线程
        //ExecutorService executorService = Executors.newFixedThreadPool(5); //固定线程数
        try {
            for (int i = 0; i < 10; i++) {
                executorService.submit(()->{
                    System.out.println(Thread.currentThread().getName());
                });
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

方法一

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
}

方法二

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}

方法三

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}

底层代码

public ThreadPoolExecutor(int corePoolSize,//核心线程数
                              int maximumPoolSize,//最大线程数
                              long keepAliveTime,//非核心线程最大等待时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//等待队列
                              ThreadFactory threadFactory,线程创建工厂
                              RejectedExecutionHandler handler //请求决绝策略) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

拒绝策略

new ThreadPoolExecutor.AbortPolicy() //线程池开启了最大线程数,线程排队也满了,则不处理这个人,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里,有点可怜
new ThreadPoolExecutor.DiscardOldestPolicy()//尝试和最早的竞争,也不会抛出异常
new ThreadPoolExecutor.DiscardPolicy() //线程池不能接收处理了,丢掉任务,不会抛出异常

原生线程池创建方法
CPU密集型:maxPool几核就是几
IO密集型:判断任务程序中耗费io的线程,15就可以创建为30个

Runtime.getRuntime().availableProcessors() //获取CPU核数

四大函数式接口新时代的程序员:lambda表达式,链式编程,函数式接口,Stream流式计算

函数

函数式接口:只有一个方法的接口,以下是常见的几种类型:
public class Demo02 { //Function 函数式接口,只有一个输入参数,有一个输出,只要是含属性接口,可以用lambda表达简化
    public static void main(String[] args) {
        Function<String,String> function1 = new Function<String, String>() {
            public String apply(String str) { return str; }
        };
        Function<String,String> function2 = (str) ->{return str;};
        System.out.println(function1.apply("123") + function2.apply("345"));
    }
}
public class Demo03 { //断定型接口
    public static void main(String[] args) {
        Predicate<String> predicate1 = new Predicate<String>() {
            public boolean test(String s) { return s.isEmpty(); }
        };
        Predicate<String> predicate2 = (str) ->{return str.isEmpty();};
        System.out.println(predicate1.test("23") + "" + predicate2.test("34"));
    }
}
public class Test03 {//消费型接口,只有输入,没有返回结果
    public static void main(String[] args) {
        Consumer<String> consumer1 = new Consumer<String>() {
            public void accept(String s) { System.out.println(s); }
        };
        Consumer<String> consumer2 = (str)-> System.out.println(str);
        consumer1.accept("we");
        consumer2.accept("ddd");
    }
}
public class Demo04 {//供给型接口,没有参数只有返回值
    public static void main(String[] args) {
        Supplier supplier1 = new Supplier<Integer>() {
            public Integer get() { return 1024; }
        };
        Supplier supplier2 = ()-> {return 1024;};
        System.out.println(supplier1.get() + "" + supplier2.get());
    }
}
stream流式计算
public class Test01 {
    public static void main(String[] args) {
        User u1 = new User(1,"a1",11);
        User u2 = new User(2,"b2",22);
        User u3 = new User(3,"c3",33);
        User u4 = new User(4,"d4",44);
        User u5 = new User(6,"f6",66);
        List<User> list = Arrays.asList(u1,u2,u3,u4,u5); //集合就是存储
        list.stream()
                .filter(user -> {return user.getId()%2==0;}) //过滤选择
                .filter(user -> {return user.getAge()>30;})
                .map(user -> {return user.getName().toUpperCase();})
                .sorted((user1,user2)->{return user2.compareTo(user1);}) //排序
                .forEach(System.out::println);
    }
}
ForkJoin(jdk1.7),将大任务划分为小任务,任务窃取(先完成任务的会帮别人分担一点任务),看一下以下几种方式:
/*
    求和计算的任务
    如何使用forkjoin
    1.forkjoinPool 通过它来执行
    2.计算任务,forkjoinPool.execute(ForkJoinTask task)
    3.计算类继承ForkjoinTask
 */
public class ForkJoinDemo extends RecursiveTask<Long> {
    private Long start;
    private Long end;
    private Long temp = 10000L;
    public ForkJoinDemo(Long start,Long end){
        this.start = start;
        this.end = end;
    }
    @Override
    protected Long compute() {
        if((end - start) < temp){
            Long sum = 0L;
            for(Long i = start; i <= end ; i++){
                sum += i;
            }
            return sum;
        }else {
            Long middle = (start + end) / 2;
            ForkJoinDemo task1 = new ForkJoinDemo(start,middle);
            task1.fork(); //执行任务,把人物压入线程队列
            ForkJoinDemo task2 = new ForkJoinDemo(middle + 1,end);
            task2.fork();
            return task1.join() + task2.join();
        }
    }
}
public class Test02 { //求和计算
    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        test1();
        test3();

    }
    public static void test1(){
        Long sum = 0L;
        Long start = System.currentTimeMillis();
        for(Long i = 0L; i <= 10_0000_0000 ; i++){
            sum += i;
        }
        Long end = System.currentTimeMillis();
        System.out.println("sum = " + sum + "时间:" + (end -start));
    }
    public static void test2() throws ExecutionException, InterruptedException {
        Long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinDemo(0L,10_0000_0000L);
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);
        Long sum = submit.get();
        Long end = System.currentTimeMillis();
        System.out.println("sum = " + sum + "时间:" + (end -start));
    }
    public static void test3(){
        Long start = System.currentTimeMillis();
        Long sum = LongStream.rangeClosed(0L,10_0000_0000L).parallel().reduce(0,Long::sum);
        Long end = System.currentTimeMillis();
        System.out.println("sum = " + sum + "时间:" + (end -start));
    }
}
异步任务,感觉和线程没有太大区别,代码如下所示
public class Test03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //没有返回值
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        });
        System.out.println("12345");
        completableFuture.get();

        //有返回值的
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(()->{
            System.out.println("有返回值");
            int i = 1/0;
            return 1024;
        });
        System.out.println(completableFuture1.whenComplete((t, u) -> {
            System.out.println("t=>" + t); //t为正常的返回值
            System.out.println("u=>" + u); //u为发生错误时候的异常信息
        }).exceptionally((e) -> {
            System.out.println(e.getMessage());
            return 233;
        }).get());
    }
}
JMM:是一种概念,一种约定

1.线程解锁前,必须把共享变量立即刷回主存
2.线程枷锁前,必须读取竹村中的最新值取到工作内存中
3.加锁和解锁是同意把锁
Volatile是java虚拟机提供轻量级的同步机制
1.保证可见性
2.不保证原子性 //AtomicInteger可以解决
3.禁止指令重排

单列模式

饿汉式

public class Hungry { //饿汉式,加载单列模式,可能会浪费内存资源
    private byte[] data1 = new byte[1024];
    private byte[] data2 = new byte[1024];
    private byte[] data3 = new byte[1024];
    private Hungry(){}
    private final static Hungry hungry = new Hungry();
    public static Hungry getHungry(){
        return hungry;
    }
}
public class LazyMan {
    private static boolean flag = false; //制裁无限获取
    private LazyMan(){
        System.out.println("dd");
        synchronized (LazyMan.class){
            if(flag == false){
                flag = true;
            }else {
                throw new RuntimeException("不要试图使用反射破坏单列模式");
            }
            //if (lazyMan != null){//反射这里没有进行初始化,所以可以通过反射无限获取
            //    throw new RuntimeException("不要试图使用反射破坏单列模式");
            //}
        }
    }
    private volatile static LazyMan lazyMan;
    public static LazyMan getLazyMan(){
        if(lazyMan==null){
            synchronized (LazyMan.class){
                if(lazyMan==null){
                    lazyMan = new LazyMan();
                    // 1.分配内存
                    // 2.执行构造方法,初始化对象
                    // 3.把这个对象指向这个空间
                    // 单线程下 执行1 2 3, 1 3 2都是一样的,但是多线程下面第一个线程执行1 3 2在3的时候就部位空,
                    // 这时候有一个线程执行第一个锁不为空,返回对象,但是并没有初始化,所以不安全,这时加上volatile,这时指令就不可以重排了
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) throws Exception {
        //LazyMan instance1 = LazyMan.getLazyMan();
        Field flag = LazyMan.class.getDeclaredField("flag");//通过反射制裁开关
        flag.setAccessible(true);

        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance1 = declaredConstructor.newInstance();

        flag.set(instance1,false);
        LazyMan instance2 = declaredConstructor.newInstance();
        System.out.println(instance1);
        System.out.println(instance2);
    }
}
public class Holder { //静态内部类解决单列模式,也是不安全的,可以使用反射构造
    private Holder(){}
    public static Holder getInstance(){
        return InnerClass.HOLDER;
    }
    public static class InnerClass{
        private static final Holder HOLDER = new Holder();
    }
}
public enum  EnumSingle {
    INSTANCE;
    public EnumSingle getInstance(){
        return INSTANCE;
    }
}
class Test{
    public static void main(String[] args) throws Exception {
        EnumSingle instance1 = EnumSingle.INSTANCE;
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSingle enumSingle1 = declaredConstructor.newInstance();
    }
}

通过如上进行代码测试,只有枚举类型才是单列安全的

CAS(compare and swap):比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行交换!如果不不是则一直循环

缺点:
1.循环会耗时
2.一次性只能保证一个共享变量的原子性
3.ABA问题

原子引用(解决ABA的问题,在数据上卖弄添加一个版本,版本更换表明被修改过的,注意-128~127才可以直接传入,超过范围请使用对象)
public class Stamp {
    public static void main(String[] args) {
        Integer ref = new Integer(2020);
        Integer newref = new Integer(2022);
        Integer three = new Integer(2024);
        AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(ref,1);
        new Thread(()->{
            int stamp = atomicInteger.getStamp();
            System.out.println("version1=>" + stamp);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("stamp1=>" + atomicInteger.compareAndSet(ref, newref, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("stamp1=>" + atomicInteger.getStamp());
            System.out.println("stamp2=>" + atomicInteger.compareAndSet(newref, ref, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("stamp2=>" + atomicInteger.getStamp());
        },"a").start();
        new Thread(()->{
            int stamp = atomicInteger.getStamp();
            System.out.println("version2=>" + stamp);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("b=>" + atomicInteger.compareAndSet(ref, three, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("b=>" + atomicInteger.getStamp());
        },"b").start();
    }
}

各种锁的理解

1.公平锁,非公平锁

公平锁:先来后到,不允许插队
非公平锁:不允许插队(默认是非公平锁)

2.可重入锁,所有的锁都是可重入锁,递归锁

sychronized:

public class Demo01 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sms();
        },"A").start();
        new Thread(()->{
            phone.sms();
        },"B").start();

    }
}
class Phone{
    public synchronized void sms(){
        System.out.println(Thread.currentThread().getName() + "sms");
        call();
    }
    public synchronized void call(){
        System.out.println(Thread.currentThread().getName() + "call");
    }
}

Lock:同意线程里面必须进行配对解锁,否则其他线程可能会因为获取不到锁而处于死锁状态

public class Demo02 {
    public static void main(String[] args) {
        Phone2 phone = new Phone2();
        new Thread(()->{
            phone.sms();
        },"A").start();
        new Thread(()->{
            phone.sms();
        },"B").start();
    }
}
class Phone2{
    Lock lock = new ReentrantLock();
    public synchronized void sms(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "sms");
            call();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public synchronized void call(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "call");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
3.自旋锁
public class Demo03 { //自旋锁
    public static void main(String[] args) {
        SpinLockTest lock = new SpinLockTest();
        new Thread(()->{
            lock.mylock();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.myunlock();
            }
        },"A").start();
        new Thread(()->{
            lock.mylock();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.myunlock();
            }
        },"B").start();
    }
}
class SpinLockTest{
    AtomicReference<Thread> atomicReference = new AtomicReference<>();
    public void mylock(){
        Thread thread = Thread.currentThread();
        while (!atomicReference.compareAndSet(null,thread)); //第二个线程会等待第一个线程释放锁之后,才能获取锁,否则死循环
        System.out.println(thread.getName() + "=>mylock");
    }
    public void myunlock(){
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread,null);
        System.out.println(thread.getName() + "=>myunlock");
    }
}
4.死锁:一般是由多个线程互相抢夺资源造成死锁
public class Demo04 {//使用jps定位问题
    public static void main(String[] args) {
        String srcA = "aaaa";
        String srcB = "bbbb";
        new Thread(new TestRunnable(srcA,srcB),"T1").start();
        new Thread(new TestRunnable(srcB,srcA),"T2").start();
    }
}
class TestRunnable implements Runnable{
    private String srcA;
    private String srcB;
    public TestRunnable(String srcA,String srcB){
        this.srcA = srcA;
        this.srcB = srcB;
    }
    public void run() {
        synchronized (srcA){
            try {
                System.out.println(Thread.currentThread().getName() + " locked=>" + srcA);
                TimeUnit.SECONDS.sleep(2);
                synchronized (srcB){
                    System.out.println(Thread.currentThread().getName() + " locked=>" + srcB);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

jps -l :查看当前进程


image.png

jstack pid:查看死锁问题


image.png

相关文章

  • JUC——检视阅读

    JUC——检视阅读 参考资料 JUC知识图参考 JUC框架学习顺序参考 J.U.C学习总结参考,简洁直观 易百并发...

  • JUC并发编程引导学习(超长篇)

    JUC并发编程学习 1、什么是JUC juc是Java并发编程的一个工具包,包名为java.util.concur...

  • juc学习

    学习网站:https://www.bilibili.com/video/BV1B7411L7tE?p=39&spm...

  • JUC源码循序渐进

    目录 必读篇 JUC源码分析—CAS和Unsafe JUC源码分析—AQS JUC锁篇 JUC源码分析-JUC锁(...

  • JUC 系列----重要概念

    系统的学习JUC并发编程,会将自己学习过程以文章的形式进行记录。我的学习路线:先从JUC的基础知识,然后使用一些J...

  • AQS同步器学习

    AQS队列同步器学习 在学习并发的时候,我们一定会接触到 JUC 当中的工具,JUC 当中为我们准备了很多在并发中...

  • Java并发之AQS同步器学习

    AQS队列同步器学习 在学习并发的时候,我们一定会接触到 JUC 当中的工具,JUC 当中为我们准备了很多在并发中...

  • JUC核心类汇总(JUC体系结构图)

    图片来源于:JUC - 类汇总和学习指南

  • LinkedBlockingQueue,LinkedBlocki

    LinkedBolckingQueue源码学习 LinkedBolckingQueue是JUC包下基于链表实现的队...

  • Java并发——AQS源码解析

    本文通过总结源码学习,来分析了解下AQS的工作原理 AQS是juc包锁实现的基础框架,研究juc包源码之前,AQS...

网友评论

      本文标题:juc学习

      本文链接:https://www.haomeiwen.com/subject/bavifrtx.html