死锁、常用类之数学、日期时间API、数组的算法升华、数组的工具类

    科技2022-08-01  91

    一.死锁:

    1.当两个或者更多隔线程互相持有对象想要的资源不放手,就会死锁

    2.当同步代码快或同步方法中出现了嵌套使用

    (1)同步代码快中,出现了另一个同步代码快,或调用了另一个同步方法

    (2)同步方法中,出现了同步代码快,或者调用了另一个同步方法,而且两者之间有使用对象要的锁对象等资源时,就有可能出现死锁状态,尽量避免

    如果出现了,要么手动停止,或者说我们要制造异常,让线程从死锁状态出来,然后再去抢夺资源。

    2.sleep方法和wait方法有什么区别?

    (1)sleep方法在Thread类中声明,是静态方法,通过Thread类.sleep()调用

    (2)wait方法在Object类中声明,是非静态方法,通过锁对象.wait() 调用

    wait方法和notify为什么要在Object中声明“

    因为wait方法必须是对象调用,但是锁对象是任意类型的对象

    那么意味着任意类型的对象都必须具备wait方法,这样的方法只能放在根父类中声明

    (2)sleep方法是必须制定时间,等待时间到了,或中途被interrupt了,就会自动醒来

    wait方法,一种是指定时间,一种是无限时等待如果无限时等待必须notify唤醒之后才能继续

    (3)当前线程遇到了sleep方法不会释放锁得,一直要等当前线程结束,才会释放锁

    public class TestSleepWait { public static void main(String[] args) { MyThread m1 = new MyThread(); MyThread m2 = new MyThread(); m1.start(); m2.start(); } } class MyThread extends Thread{ private int num = 1; public void run(){ synchronized (MyThread.class) { System.out.println(num++); /* try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }*/ try { MyThread.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }

    二、常用类之数学

    1.java.long,math类

    (1)public static double sqrt(double a):求x的平方根

    (2)public static double random)(): 返回带正号的double 值,大于等于0.0且小于1.0

    (3)public static double pow (double a, double b):返回第一个参数的第二个参数次幂,即a的b次方

    (4)public static double abs (double a ) 返回绝对值

    (5)public static double max(double a, double b):求a和b的最大值

    (6)public static double min(double a, double b):求a和b的最小值

    (7)public static double floor (double a);向下取整

    ​ public static double ceil (double a);向上取整

    ​ public static long round (double a);四舍五入取整(最接近的整数)

    ​ -x.5比较特殊

    2.java.math包

    java.math,BigDecimal:定点小数和大的小数,可以精确到小数点后n位,如果可以整除,可以用该方法,如果不能整除,说明保留小数点后多少位

    float 和double :浮点数,不精确.

    java.math.BigInerger:表示大整数

    用法 BigInteger ig1 =new Big Integer(参数);

    3.java.util,Random类:产生随机数

    可以产生随机的整数、小数、boolean等所有数据类型

    Math.random只能产生【0,1】之间的随机小数

    Random random = new Random();

    三、日期时间API

    1.jdk中的日期时间API经历了三代

    第一代:java.util.Date等

    第二代:java.util.Calendar等

    第三代:java.time包及其子包的类型

    2.java.util.Date类

    (1)Date() 获取当前系统时间

    (2)Date(long time),根据指定的毫秒值,获取对应的日期时间

    (2)Long getTime()获取当前系统时间距离1970-1-1凌晨的毫秒值

    等同于 System.currentTimeMillis()

    问题:为什么开始于1970年

    Unix操作系统在1970年设计数来,把1970-1-1凌晨作为计算机时间的原始起点

    Date类型大部分都是已过时的方法

    3.java.util.Calendar类

    他是一个抽象类,

    如何创建对象:

    (1)创建它子类对象

    (2)在Calendar类中提供静态方法

    Date和Calendar:

    (1)使用麻烦

    无法获取满足本地人阅读习惯的日期时间对象

    需要借助DateFormat,它是抽象类,他有一非常

    (2)可变对象:在开发中,日期对象,某个对象某个瞬间的日期时间,是不应该变的

    (3)没有考虑闰秒

    4.java8引入,java.time包:包含值对象的基础包

    (1)本地的日期类型的API

    LocalDate:日期、

    Localtime:时间

    LocalDateTime:日期和时间

    LocalDateTime.now()方法指当前时间

    LocalDateTime.of()方法可以指定时间

    .isLeapYear():判断指定时间是不是闰年

    修改日期或时间对象会返回一个新的对象结果,必须接受

    5.java.long.System

    (1)System.out 对象

    (2)System.in 对象

    (3)public static long currenTimeMillis():获取距离1970年的时间

    (4)public static void arraycopy(Object src,int srcPos,Object,destPos,int length)

    src:原数组

    srcPos:原数组的起始位置

    dest:目标数组

    destPos:目标数组的起始位置

    length:要挪动的元素的长度

    total个元素, arr.length长度 假设length = 10, total = 7, 元素的下标[0,6] i=2 移动[3],[4],[5],[6] 删除arr数组的[i] 元素: System.arraycopy(arr, i+1, arr, i, total-i-1) i=2 移动[2],[3],[4],[5],[6] 插入arr数组的[i]元素: System.arraycopy(arr, i, arr, i+1, total-i)

    (5)public static void gc():通知GC工作,进行垃圾回收,通知后,不代表GC线程立刻工作。 (6)public static void exit(int status):终止当前运行的Java虚拟机。 该参数作为状态代码; 按照惯例,非零状态码表示异常终止。 (7)public static Properties getProperties():获取所有的系统数属性

    6.java.lang.Runtiam类

    runtime.getRrntime()代表JVM的运行环境

    四、数组的算法升华

    1.数组的反转

    方案一:

    先新建一个数组,然后把元素按照反转之后的正确的顺序放进去,指向新的数组

    缺点:浪费空间

    方案二:

    首尾交换

    public class TestArray { @Test public void test01(){ int[] arr = {1,2,3,4,5}; //反转之后:arr中{5,4,3,2,1} //方案一:先新建一个数组,然后把元素按照反转之后的正确的顺序放到新数组中,让arr指向新数组 int[] newArr = new int[arr.length]; //把arr中的元素逆序放到newArr for (int i = 0; i < newArr.length; i++) { /*newArr[0] = arr[arr.length-1]; newArr[1] = arr[arr.length-2];*/ newArr[i] = arr[arr.length-1-i]; } //让arr指向新的数组 arr = newArr; //遍历 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } @Test public void test02(){ int[] arr = {1,2,3,4,5}; //首尾交换 /* 1 2 3 4 5 1和5换 2和4换 5个元素换2次 10个元素:5次 交换的次数 = 数组的长度/2(整数与整数相除只保留整数部分) */ //循环的次数 = 交换的次数 for (int i = 0; i < arr.length/2; i++) { //交换的过程 int temp = arr[i]; arr[i] = arr[arr.length-1-i]; arr[arr.length-1-i] = temp; } //遍历 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }
    2.数组的扩容
    public class TestArray2 { @Test public void test01(){ int[] arr = {1,2,3,4,5}; //我想要在当前数组的基础上,增加一个元素6,放在最后 /* 思路: (1)创建新数组 (2)把原来的元素复制过程 (3)把新元素放进去 (4)让arr指向新数组 */ int[] newArr = new int[arr.length+1]; for (int i=0; i <arr.length; i++){ newArr[i] = arr[i]; } // newArr[newArr.length-1] = 6; arr = newArr; arr[arr.length-1] = 6; } }
    3、数组的插入
    ublic class TestArray3 { @Test public void test01(){ int[] arr = {1,2,3,4,5}; //需求:要在arr[1]的位置插入6,结果{1,6,2,3,4,5} /* (1)先创建一个新数组newArr,新数组的长度 > 旧数组 (2)把arr中[0,index-1]的元素放到newArr中 (3)把新元素放到newArr中[index] (4)把arr中[index,arr.length-1]放到newArr中 (5)最后arr指向newArr */ int[] newArr = new int[arr.length+1]; int index = 1;//插入的位置 int value = 6;//插入的值 for (int i=0; i<index; i++){ newArr[i] = arr[i]; } newArr[index] = value; for(int i=index; i<arr.length; i++){ newArr[i+1] = arr[i]; } arr = newArr; //遍历 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } @Test public void test02(){ String[] arr = {"hello","java","world",null,null}; /* 要在index=1的位置插入"atguigu",结果{"hello","atguigu","java","world",null}; 思路: (1)把index及其后面的元素后移 (2)然后把新元素放到[index] */ int total = 3; int index = 1;//插入的位置 System.arraycopy(arr, index, arr, index+1, total-index); arr[index] = "atguigu"; total++; //遍历 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } /* 在arr[index]位置插入value */ public int[] insert(int[] arr,int index, int value){ /* 方案一: (1)先创建新数组,扩容 (2)把arr的所有元素,原封不动的赋值到新数组newArr (3)再把index位置及其后面的元素后移 (4)把value放到index位置 (5)返回新数组 */ int[] newArr = new int[arr.length+1]; for (int i = 0; i < arr.length; i++) { newArr[i] = arr[i]; } System.arraycopy(newArr, index, newArr, index+1, arr.length-index); newArr[index]=value; return newArr; } @Test public void test03(){ int[] arr = {1,2,3,4,5}; int index = 1; int value = 6; arr = insert(arr, index, value); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }
    4、数组的元素删除
    public class TestArray4 { @Test public void test01(){ String[] all = {"hello","java","world",null,null}; //删除index=1位置的元素 int index = 1; int total = 3; //把index+1后面的元素往前移动 System.arraycopy(all, index+1, all, index, total-index-1); all[total-1] = null; //遍历 for (int i = 0; i < all.length; i++) { System.out.println(all[i]); } } }
    5.数组的二分查找

    之前:数组的查找,是顺序查找,从[0]开始,挨个比较是否目标对象,如果是,找到了,如果不是,一直找到最后 现在:二分查找,又称为折半查找 二分查找有要求,数组必须是有序的

    public class TestArray5 { @Test public void test01(){ int[] arr = {2,5,7,8,10,15,18,20,22,25,28};//数组是有序的 int value = 18; //查找value是否在arr中,如果在,打印下标,如果不在,说明不在 int left = 0; int right = arr.length-1; int mid = (left +right)/2; int index = -1; while(left <= right){ if(arr[mid] == value){ index = mid; break; }else if(value > arr[mid]){ left = mid +1; }else{ right = mid - 1; } mid = (left + right) / 2; } if(index==-1){ System.out.println("没找到"); }else{ System.out.println("找到了,下标是:" + index); } } }
    6.数组的直接排序=冒泡
    public class TestArray6 { @Test public void test01(){ int[] arr = {49,38,65,97,76,13,27,49}; /* 直接选择排序: 思路:每一轮,找出本轮未排序元素中的最小/最大值,看它是否在正确的位置,如果不在,就与该正确位置的元素交换,这样经过多轮之后,实现排序 最坏的情况:arr.length-1轮 {49,38,65,97,76,13,27,49} 从小到大 第一轮:在[0,arr.length-1]范围的最小值 arr[5]=13是最小的,它应该在arr[0],所以要arr[0]与arr[5] {13,38,65,97,76,49,27,49} 第二轮:在[1, arr.length-1]范围找最小值 arr[6]=27是最小的,它应该在arr[1],所以要arr[1]与arr[6] {13,27,65,97,76,49,38,49} 。。。。 */ for (int i=0; i<arr.length-1; i++){ //第1轮:i=0, j=0到arr.length-1 //第2轮:i=1, j=1到arr.length-1 //第3轮:i=2, j=2到arr.length-1 //... //第n轮:i=arr.length-2, j=arr.length-2到arr.length-1 //j=i int min = arr[i];//假设本轮的第一个元素最小 int index = i;//本轮最小值的下标 for(int j=i; j<=arr.length-1; j++){ if(arr[j] < min){ min = arr[j]; index = j; } } if(index != i){ //交换 arr[index] 和 arr[i] int temp = arr[index]; arr[index] = arr[i]; arr[i] = temp; } } //结果 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } @Test public void test02() { int[] arr = {49, 38, 65, 97, 76, 13, 27, 49}; /* 第一轮:拿所有元素与arr[0]位置的元素比较,有比它小的,就交换 第一次:{38, 49, 65, 97, 76, 13, 27, 49}; 第二次: 第三次: 第四次: 第五次:{13, 49, 65, 97, 76, 38, 27, 49}; 第六次: 第七次: 第二轮:拿所有元素与arr[1]位置的元素比较,有比它小的,就交换 。。。 */ for(int i=0; i<arr.length-1; i++){ for(int j=i; j<=arr.length-1; j++){ if(arr[j] < arr[i]){ int temp = arr[j]; arr[j] = arr[i]; arr[i] = temp; } } } } @Test public void test03(){ int[] arr = {49,38,65,97,76,13,27,49}; for (int i=0; i<arr.length-1; i++){ int index = i;//本轮最小值的下标 for(int j=i; j<=arr.length-1; j++){ if(arr[j] < arr[index]){ index = j; } } if(index != i){ //交换 arr[index] 和 arr[i] int temp = arr[index]; arr[index] = arr[i]; arr[i] = temp; } } //结果 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }

    五、数组的工具类

    java.util.Arrays工具类:此类包含用来操作数组(比如排序和搜索)的各种方法。 开发中:能够用API的方法,肯定是最简洁的, 面试中,需要知道底层是如何实现的,甚至有些算法要手动会实现。

    System.arraycopy这个方法和数组关系,为啥在System类中,不在Arrays类? 因为版本的问题。JDK1.0时候,还没有Arrays工具类,但是arraycopy这个方法已经在使用了, 当时没地方放这个方法,只好放在系统类中。后期所有和数组有关的方法都在Arrays类中。

    (1)public static int binarySearch(int[] a, int key):二分查找 如果它包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。插入点 被定义为将键插入数组的那一点: 它有很多重载形式,形参的类型不同

    (2)public static int[] copyOf(int[] original,int newLength):复制数组 它有很多重载形式,形参的类型不同

    (3)public static int[] copyOfRange(int[] original,int from, int to) 它有很多重载形式,形参的类型不同

    (4)public static boolean equals(int[] a, int[] a2):比较两个数组是否相同 它有很多重载形式,形参的类型不同

    (5)public static void fill(int[] a,int val):用val填充整个数组 它有很多重载形式,形参的类型不同

    (6)public static void sort(int[] a) :对指定的 int 型数组按数字升序进行排序。该排序算法是一个经过调优的快速排序法 它有很多重载形式,形参的类型不同

    (7)public static void sort(Object[] a):给对象数组排序,按升序排列,要求元素必须是java.lang.Comparable public static void sort(Object[] a, Comparator c):按升序排列,需要一个Comparator实现类对象

    (8)public static String toString(int[] a) 它有很多重载形式,形参的类型不同

    Processed: 0.013, SQL: 8