尚硅谷Java第三季--1.javaj基础

在这里插入图片描述

1. javaj基础

Java字符串常量池

public class StringPools58Demo {
    public static void main(String[] args) {
        /*
        (1).str1
        str1 会有4个对象
           一个StringBuilder、
           一个58 ldc、
           一个tongcheng ldc、
           String
           这个时候常量池中没有58tongcheng这个ldc在
        str1.intern():在jdk7后,会看常量池中是否存在,如果没有,它不会创建一个对象,
                      如果堆中已经这个字符串,那么会将堆中的引用地址赋给它
                      所以这个时候str1.intern()是获取的堆中的
        * */
        String str1=new StringBuilder("58").append("tongcheng").toString();
        System.out.println(str1);
        System.out.println(str1.intern());
        System.out.println(str1==str1.intern());//true
        System.out.println();

        /*
        sum.misc.Version类会在JDK类库的初始化中被加载并初始化,而在初始化时它需要对静态常量字
        段根据指定的常量值(ConstantValue)做默认初始化,此时sum.misc.Version.launcher静态常
        量字段所引用的"java"字符串字面量就被intern到HotSpot VM的字符串常量池 - StringTable
        里了
        str2对象是堆中的
        str.intern()是返回的是JDK出娘胎自带的,在加载sum.misc.version这个类的时候进入常量池
        */
        String str2=new StringBuilder("ja").append("va").toString();
        System.out.println(str2);
        System.out.println(str2.intern());
        System.out.println(str2==str2.intern());//false ,只有jdk自带的字符串如"java"字符串是false,其他字符串都是true

    }
}


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

利扣算法题:两数之和

在这里插入图片描述

/*
    题目:
    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,
    并返回他们的数组下标你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使
    用两遍。
* */
public class TwoSumDemo {
    public static void main(String[] args) {
        int[]nums ={2, 7, 11, 15};
        int target = 99;
        //int[]indexCollection=twoSum1(nums,target);
        int[]indexCollection=twoSum2(nums,target);
        if(indexCollection!=null){
            for (int index : indexCollection) {
                System.out.print(index+" ");
            }
        }
    }

    //1.暴力法:
    //通过双重遍历数组中所有元素的两两组合,当出现符合的和时返回两个元素的下标
    public static int[] twoSum1(int[] nums, int target) {
        for (int i = 0; i < nums.length; i++) {
            for (int j = i+1; j <nums.length ; j++) {
                if(target-nums[i]==nums[j]){
                    return new int[]{i,j};
                }
            }
        }
        return null;
    }
    //2.哈希(更优解法)
    public static int[] twoSum2(int[] nums, int target){
        Map<Integer,Integer> map=new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int param=target-nums[i];//2 7
            if(map.containsKey(param)){
                return new int[]{map.get(param),i};
            }
            map.put(nums[i],i);
            //map  k存数组值  v存下标
                    2          0
        }
        return null;
    }
}

java并发编程(juc)

在这里插入图片描述

可重入锁(递归锁)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
隐式(自动挡)是指:jvm自动帮我们加锁释放锁
显示(收动挡)是指:需要自己显示的lock和unLock

在这里插入图片描述

sychronized

隐式锁:(即synchronized关键字使用的锁)默认是可重入锁(同步块、同步方法)
原理如下:

  • 每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针
  • 当执行monitorenter时,如果目标锁对象的计数器为零,那么说明它没有被其他线程持有,Java虚拟机会将该锁对象的持有线程设置为当前线程,并且将其计数器加1,否则需要等待,直至持有线程释放该锁
  • 当执行monitorexit时,Java虚拟机则锁对象的计数器减1。计数器为零代表锁已经被释放

反编译底层原理
在这里插入图片描述

//1.同步代码块

//1.同步代码块
public class SychronizedDemo {
    Object object=new Object();

    public void sychronizedMethod(){
       new Thread(()->{
           synchronized (object){
               System.out.println(Thread.currentThread().getName()+"\t"+"外层....");
               synchronized (object){
                   System.out.println(Thread.currentThread().getName()+"\t"+"中层....");
                   synchronized (object){
                       System.out.println(Thread.currentThread().getName()+"\t"+"内层....");
                   }
               }
           }
       },"A").start();
    }
    public static void main(String[] args) {
        new SychronizedDemo().sychronizedMethod();
        /*
        输出结果:
            A	外层....
            A	中层....
            A	内层....
        * */
    }
}

//2.同步方法

public class ReEnterLockDemo {
    public synchronized void m1() {
        System.out.println("=====外");
        m2();
    }
    public synchronized void m2() {
        System.out.println("=====中");
        m3();
    }
    public synchronized void m3() {
        System.out.println("=====内");
    }

    public static void main(String[] args) {
        new ReEnterLockDemo().m1();
    }

}

输出结果

=====外
=====中
=====内

ReentrantLock

显示锁:(即lock)也有ReentrantLock这样的可重入锁
(注意:有多少个lock,就有多少个unlock,他们是配对使用的;如果多一个或者少一个会使得其他线程处于等待状态)

在这里插入图片描述

class Phone2{
   static ReentrantLock reentrantLock=new ReentrantLock();

    public static void sendSms(){
        reentrantLock.lock();
        /*
        //reentrantLock.lock();
        注意有多少个lock,就有多少个unlock,他们是配对使用的
        如果多了一个lock(),那么会出现线程B一直处于等待状态
        * */
        reentrantLock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"\t"+"sendSms");
            sendEmails();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
        }
    }

    private static void sendEmails() {
        reentrantLock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"\t"+"sendEmails...");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
        }
    }
}
public class ReentrantLockDemo {
    public static void main(String[] args) {
        Phone2 phone2=new Phone2();
        new Thread(()->{phone2.sendSms();},"A").start();
        new Thread(()->{phone2.sendSms();},"B").start();
    }
}

LockSupport

LockSupport就是对线程唤醒机制(wait/notify)的升级加强版
在这里插入图片描述
在这里插入图片描述
3种让线程等待唤醒的方法:
在这里插入图片描述

synchronized -->wait( )和notify( )

Object类中wait( )和notify( )实现线程的等待唤醒
wait( ):阻塞线程
notify( ):唤醒线程

1. wait和notify方法必须要在synchronized 同步块或同步方法里且成对出现使用。
2. 必须先wait后再notify(如果先notify后wait会出现另一个线程一直处于等待状态)

正常使用
在这里插入图片描述

  • wait和notify方法必须要在synchronized 同步块或同步方法里且成对出现使用。 wait和notify方法两个都去掉同步代码块后看运行效果出现异常情况:
Exception in thread “A” Exception in thread “B”
java.lang.IllegalMonitorStateException

wait和notify方法不能脱离synchronized 同步块或同步方法使用
在这里插入图片描述
不是synchronized 同步块或同步方法使用
在这里插入图片描述
在这里插入图片描述

  • 先notify后wai
    先wait后notify才可以(如果先notify后wait会出现另一个线程一直处于等待状态)

在这里插入图片描述
在这里插入图片描述

ReentrantLock–>await()和signal()

Condition接口中的await和signal方法实现线程等待和唤醒
(出现的问题和object中wait和notify一样)

1. await()和signal()方法必须要在lock和unLock同步块或同步方法里且成对出现使用。
2. 必须先await后再signal(如果先signal后await会出现另一个线程一直处于等待状态)

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

public class LockDemo {
    static Object object=new Object();
    public static void main(String[] args) {
        Lock lock=new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(()->{
            //如果把下行这句代码打开,先signal后await,会出现A线程一直处于等待状态
            //try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName()+"\t"+"coming....");
                condition.await();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
            System.out.println(Thread.currentThread().getName()+"\t"+"END....");
        },"A").start();

        new Thread(()->{
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName()+"\t"+"唤醒A线程****");
                condition.signal();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"B").start();
    }
}
LockSupport–>park()和unpark()
  1. 不用必须写在锁代码块中
  2. 先unpark(),唤醒再park()阻塞,阻塞无效
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

/*
(1).阻塞
 (permit默认是O,所以一开始调用park()方法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,
 park方法会被唤醒,然后会将permit再次设置为O并返回)
 static void park()
 static void park(Object blocker)
(2).唤醒
static void unpark(Thread thread)
 (调用unpark(thread)方法后,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,
 permit值还是1)会自动唤醒thread线程,即之前阻塞中的LockSupport.park()方法会立即返回)
 static void unpark(Thread thread)
* */
public class LockSupportDemo {
    public static void main(String[] args) {

        Thread t1=new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t"+"coming....");
            LockSupport.park();
            /*
            如果这里有两个LockSupport.park(),因为permit的值为1,上一行已经使用了permit
            所以下一行被注释的打开会导致程序处于一直等待的状态
            * */
            //LockSupport.park();
            System.out.println(Thread.currentThread().getName()+"\t"+"被B唤醒了");
            },"A");
        t1.start();

        //下面代码一行是为了A线程先执行
       try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}

        Thread t2=new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t"+"唤醒A线程");
            //有两个LockSupport.unpark(t1),由于permit的值最大为1,所以只能给park一个通行证
            LockSupport.unpark(t1);
            //LockSupport.unpark(t1);
        },"B");
        t2.start();
    }
}

在这里插入图片描述

面试题
在这里插入图片描述

AQS

**AQS --> AbstractQueuedSynchronizer (抽象队列同步器): **
用来管理线程的:一个int状态变量+一个队列
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
是一个抽象的类
在这里插入图片描述

和AQS有关的锁
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
锁和AQS同步器的关系
在这里插入图片描述
AQS管理多线程
在这里插入图片描述

A

AQS源码解析

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

AQS内部架构

AQS内部架构图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ReentrantLock和AQS的关系

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

ReentrantLock的内部结构

在这里插入图片描述

公平锁和非公平锁

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多个线程抢锁AQS的执行流程
在这里插入图片描述

在这里插入图片描述
第一个哨兵节点的作用
在这里插入图片描述

在这里插入图片描述

A释放锁 --> B获取锁
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值