@CLSChen
2019-09-22T11:34:02.000000Z
字数 24793
阅读 1869
Java 编程
Java泛型详解:https://www.cnblogs.com/coprince/p/8603492.html
<>,然后在调用它的时候用具体的类型来替换<>里的内容。
Generic<T> //泛型类T //泛型类型参数
List arrayList = new ArrayList();arrayList.add("aaaa");arrayList.add(100);for(int i = 0; i< arrayList.size();i++){String item = (String)arrayList.get(i);Log.d("泛型测试","item = " + item);}// 运行结果java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String在运行的时候检测出来,不可以将Integer类转换成String,报错。
List arrayList<String>= new ArrayList<>();arrayList.add("aaaa");arrayList.add(100);// 编辑器报错,不可以向其中添加Integer。
int是不可以的。 Integer。Java会自动将5包装为new Integer(5),这个过程称为自动装箱。
ArrayList<Integer> intList = new ArratList<>();intList.add(100);// 可以直接用100,而不用new Integer(100)
JDK1.5之前没有使用泛型的时候,输出列表内的元素需要强制类型转换,因为当时的ArrayList不知道其中存储的是什么类型的对象。
// 未给ArrayList声明对象类型ArrayList dates = new ArrayList();dates.add(new Date());// 因此要进行强制类型转换Date date1 = (Date)dates.get(0);
JDK1.5之后,ArrayList知道自己储存的是Date对象。
// 声明ArrayList泛型的对象为Date,ArrayList知道自己储存的是Date对象。ArrayList<Date> dates = new ArrayList<>();dates.add(new Date());// 可以直接读取Date date1 = dates.get(0);
但是,当编译结束后,Java处理器仍然将泛型转化为普通类型(类型消除),并在最后加一个强制类型转换。也就是说,最后都会回到第一种情况(笑)。泛型只在编译的时候有效果,不会进入到运行时段。
因此,泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。因此对其使用instanceof是错误的。我们创建两个泛型列表。
ArrayList<String> list1 = new ArrayList<>;ArrayList<Integer> list2 = new ArrayList<>;
ArrayList<String>和ArrayList<Integer>是两种类型,但是,运行时只有一个ArrayList类会被加载到JVM中。list1和list2都是ArrayList类的实例,因此,下面两条语句的执行结果都为true:
list1 instanceof ArrayList;list2 instanceof ArrayList;
list1 instanceof ArrayList<String>;
// 不能使用[泛型类型参数]创建对象和数组E test = new E();E[] testarray = new E[5];// 可以使用强制类型转换配合object类来做,但是仍然会有警告。E[] testarray = (E[])new object[5];---// 使用[泛型类]创建对象是可以的ArrayList<String> test = new ArrayList<String>;// 但是使用[泛型类]创建数组也是不允许的ArrayList<String>[] testarray = new ArrayList<String>[];// 同样也可以使用强制类型转换,但是也会有警告ArrayList<String>[] testarray = (ArrayList<String>[])new ArrayList<String>[];---// 静态方法和异常类不能是泛型的。
Integer是Number的子类,但是ArrayList<Integer> 不是ArrayList<Number>的子类,虽然同一种泛型可以对应多种类型,这几种类型可能还会有些子类父类的关系,但是不同的泛型类实例是不兼容的。<T>,而创建类实例时需要指定对象类型如<String>,但是构造方法并不需要加,构造方法保持原样。
// 泛型类定义class Generic<T>{// 构造方法public Generic();}// 创造类实例new Generic<String>
<T>中的T),在很多方法中都会用到T,但是不是用到T的方法就是泛型方法,泛型方法有自己的定义。public和返回值之间加了个<T>,只有这样单独声明的方法才是泛型方法。泛型方法的泛型不收泛型类限制,可以向里面传入任何类型,而不只是类创建时声明的那个类型,泛型方法和泛型类是独立的。
public static <T> void print(E[] list){};
public class GenericTest {//这个类是个泛型类,在上面已经介绍过public class Generic<T>{private T key;public Generic(T key) {this.key = key;}//我想说的其实是这个,虽然在方法中使用了泛型,但是这并不是一个泛型方法。//这只是类中一个普通的成员方法,只不过他的返回值是在声明泛型类已经声明过的泛型。//所以在这个方法中才可以继续使用 T 这个泛型。public T getKey(){return key;}/*** 这才是一个真正的泛型方法。* 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T* 这个T可以出现在这个泛型方法的任意位置.* 泛型的数量也可以为任意多个* 如:public <T,K> K showKeyName(Generic<T> container){* ...* }*/public <T> T showKeyName(Generic<T> container){System.out.println("container key :" + container.getKey());T test = container.getKey();return test;}/*** 这个方法是有问题的,编译器会为我们提示错误信息:"UnKnown class 'E' "* 虽然我们声明了<T>,也表明了这是一个可以处理泛型的类型的泛型方法。* 但是只声明了泛型类型T,并未声明泛型类型E,因此编译器并不知道该如何处理E这个类型。*/public <T> T showKeyName(Generic<E> container){...}/*** 这个方法也是有问题的,编译器会为我们提示错误信息:"UnKnown class 'T' "* 对于编译器来说T这个类型并未项目中声明过,因此编译也不知道该如何编译这个类。* 所以这也不是一个正确的泛型方法声明。*/public void showkey(T genericObj){}}
public class GenericFruit {class Fruit{@Overridepublic String toString() {return "fruit";}}class Apple extends Fruit{@Overridepublic String toString() {return "apple";}}class Person{@Overridepublic String toString() {return "Person";}}class GenerateTest<T>{public void show_1(T t){System.out.println(t.toString());}//在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。//由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。public <E> void show_3(E t){System.out.println(t.toString());}//在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。public <T> void show_2(T t){System.out.println(t.toString());}}public static void main(String[] args) {Apple apple = new Apple();Person person = new Person();GenerateTest<Fruit> generateTest = new GenerateTest<Fruit>();//apple是Fruit的子类,所以这里可以generateTest.show_1(apple);//编译器会报错,因为泛型类型实参指定的是Fruit,而传入的实参类是Person//generateTest.show_1(person);//使用这两个方法都可以成功generateTest.show_2(apple);generateTest.show_2(person);//使用这两个方法也都可以成功generateTest.show_3(apple);generateTest.show_3(person);}}
public static <T> void print(T t){}// 注意static位置在<T>前
Public static <T extends Generic> void print(T t){}
<E>等同于<E extends Object>Generic<E> <E> void max(E o1,E o2)<E extends Comparable<E>>,这有两个含义,一是它指定E为Comparable的接口实例,其次,它指定Comparable进行比较的元素是E类型的。
package chapter19;public class GenericSort {public static void main(String[] args) {// Create an Integer arrayInteger[] intArray = { new Integer(2), new Integer(4), new Integer(3) };// Create a Double arrayDouble[] doubleArray = { new Double(3.4), new Double(1.3), new Double(-22.1) };// Create a Character arrayCharacter[] charArray = { new Character('a'), new Character('J'), new Character('r') };// Create a String arrayString[] stringArray = { "Tom", "Susan", "Kim" };// Sort the arrayssort(intArray);sort(doubleArray);sort(charArray);sort(stringArray);// Display the sorted arraysSystem.out.print("Sorted Integer objects: ");printList(intArray);System.out.print("Sorted Double objects: ");printList(doubleArray);System.out.print("Sorted Character objects: ");printList(charArray);System.out.print("Sorted String objects: ");printList(stringArray);}/** Sort an array of comparable objects */● public static <E extends Comparable<E>> void sort(E[] list) {E currentMin;int currentMinIndex;for (int i = 0; i < list.length - 1; i++) {// Find the minimum in the list[i..list.length-1]currentMin = list[i];currentMinIndex = i;for (int j = i + 1; j < list.length; j++) {if (currentMin.compareTo(list[j]) > 0) {currentMin = list[j];currentMinIndex = j;}}// Swap list[i] with list[currentMinIndex] if necessary;if (currentMinIndex != i) {list[currentMinIndex] = list[i];list[i] = currentMin;}}}/** Print an array of objects */public static void printList(Object[] list) {for (int i = 0; i < list.length; i++)System.out.print(list[i] + " ");System.out.println();}}
// 非受限通配<?>// 受限通配<? extends SuperClass>// 下限通配<? super T>
创建一个数据结构就是创建这个类的一个实例。
Java中的两种容器
1.存储相同元素的合集collection
2.存储键值对的映射表map
add()只能在子类里实现,因为它涉及到具体的类型。List接口,AbstractList抽象类,ArrayList类。用户可以简单的定义一个具体类继承一个抽象类,这样就不用实现接口的所有方法。这些抽象类被称为便利抽象类。
所有的合集继承于Collection接口,它提供了往合集中添加和删除元素的方法,如add,remove,retain(并、差、交)和相应的addAll,removeAll,retainAll,前者操纵单个对象,后者操纵整个合集。

AbstractCollection实现了除add()和iterator()(迭代器)这种以外的所有方法。Iterator<E>
// 创建一个列表alistArrayList<String> alist = new ArrayList<String>();alist.add("new york")alist.add("new york2")// 为alist生成一个迭代器Iterator<String> alistRator = alist.iterator();// 使用迭代器来访问列表while(alistRator.hasNext()){System.out.println("iterator.next().toUpperCase()" + " ");}//输出:new york new york2
ArrayList<String> alist = new ArrayList<String>();alist.add("new york")alist.add("new york2")for(String a:alist){System.out.println("a.toUpperCase()" + " ");}
Collection接口与Iterator接口 
ArrayList和LinkedList数组是最优方案,如果需要改变长度,那么ArrayList是最优方案,如果还想在表头修改数据,那么LinkedList是最优方案。(注意:ArrayList也能在表头修改,但是效率会低一些,因为所有元素需要后移)
listIterator()方法和listIterator(startIndex)方法,它们都继承了Iterator接口并拓展它。它们会返回一个针对该列表元素的迭代器,并且支持双向遍历。 ArrayList的动态创建: trimToSize()方法将数组缩小到线性表的大小。
ArrayList不能在表头插入或删除元素。如果需要在表头插入元素,就需要用到LinkedList类。
LinkedList类用链表储存元素

// 非常低效for (int i = 0; i < list.size(); i++){a = get(i);}// 高效for(int i : list){a = i;}
comparable接口,可以通过里面的compareTo方法来比较实现了comparable接口的两个元素。comparator)来比较不同类的元素。
// 如果前面的小于后面的,返回一个负值,相等为0,大于为正值。public int compare(T element1, T element2)
// 注意,该方法实现了Serializable接口来进行序列化,在实现comparator接口的地方最好都在后面跟上Serializable接口。public class Geocom● implements Comparator<GeometricObject>, java.io.Serializable{public int compare(GeometricObject o1, GeometricObject o2){double area1 = o1.getArea();double area2 = o2.getArea();if(area1 > area2)return 1;else if(area1 < area2)return 0;else}}

Collections.sort
// 使用Arrays的静态asList方法来方便的创建列表List<String> list = Arrays.asList("red","green","blue");// 使用sort静态方法来排序Collections.sort(list);// 使用重载的sort方法来调用reverseOrder比较器来倒序排序Collections.sort(list, Collections.reverseOrder);
List<String> list1 = Arrays.asList("red","green","blue");List<String> list2 = Arrays.asList("yellow");Collections.copy(list1,list2);// list1 : yellow green blue
栈是一种后进先出的结构。
Vector中的方法



import java.util.*;public class PriorityQueueDemo {public static void main(String[] args) {● PriorityQueue<String> queue1 = new PriorityQueue<>();queue1.offer("Oklahoma");queue1.offer("Indiana");queue1.offer("Georgia");queue1.offer("Texas");System.out.println("Priority queue using Comparable:");while (queue1.size() > 0) {System.out.print(queue1.remove() + " ");}● PriorityQueue<String> queue2 = new PriorityQueue<>(4, Collections.reverseOrder());queue2.offer("Oklahoma");queue2.offer("Indiana");queue2.offer("Georgia");queue2.offer("Texas");System.out.println("\nPriority queue using Comparator:");while (queue2.size() > 0) {System.out.print(queue2.remove() + " ");}}}//输出结果:> Priority queue using Comparable:> Georgia Indiana Oklahoma Texas> Priority queue using Comparator:> Texas Oklahoma Indiana Georgia

Set<String> hashSet = new HashSet<>();// 等价于Set<String> hashSet = new HashSet<>(16, 0.75);

Ser<GeometricObject> set = new TreeSet<>(new GeoComparator);

// 默认按插入顺序排序Map<String,Integer> linkmap = new LinkedHashMap<>();// 按照访问顺序排序(最后访问的在最后面)Map<String,Integer> linkmap = new LinkedHashMap<>(16, 0.75, true);
Map<String, Integer> tmap = new TreeMap<>();Map<String, Integer> tmap = new TreeMap<>(new Comparator);

EMPTY_SET、EMPTY_LIST、EMPTY_MAP
O(logn)=O(log2 n)=O(loga n),所以常量的底可忽略。
public static int fib(int n){if(n == 0)return 0;else if (n <= 2)return 1;elsereturn fib(n - 1) + fib(n - 2);}
public static int fib(int n){int f0 = 0;int f1 = 1;int f2 = 1;if(n == 0)return 0;else if (n <= 2)return 1;for(int i = 3; i < n; i++){f0 = f1;f1 = f2;f2 = f0 + f1;}}
public static int fib(int n, int ppre, int pre){if(n <= 1)return ppre;elsereturn fib(int n - 1, int pre, int ppre + pre);}main{fib(5, 1, 1);}
用gcd(m, n)表示求m和n的最大公约数。如果m % n=0,那么gcd(m, n)为n。否则,gcd(m, n)就是gcd(n, m % n)。// 时间复杂度为O(logn)public static int gcd(int m, int n){if(m % n == 0)return n;elsereturn gcd(n, m % n);}
// 计算很多次for(int i = 0; i < (int)math.sqrt(number); i++)// 整个for循环只计算一次int sqrtnum = (int)math.sqrt(number);for(int i = 0; i < sqrtnum; i++)
O(n^2)a[i]为插入元素。将插入元素存储在临时变量cur中。 (int j = i;;j--),这样在后移的时候不会覆盖后面的元素。 (a[j - 1])>cur,则将该元素后移一位。 b[j - 1] = b[j],然后向前遍历j--,直到前一位不比cur大为止b[j - 1] > cur。 b[j]的位置上空出来了,那么我们就插入这个空档b[j] = cur;为什么是j?因为j-1小于cur嘛,放到j-1肯定不对,放到j刚刚好。
public static void main(String[] args) {int[] a = {1, 3, 5, 7, 24, 73, 72, 2};int[] b = new int[8];// b数组的大小要和a一样。int cur = 0;for (int i = 0; i < a.length; i++) {cur = a[i];int j;// importantfor (j = i; j > 0 && b[j - 1] > cur; j--) { // 4b[j] = b[j - 1];}b[j] = cur; // 5}for (int x : b) {System.out.print(x + " ");}}
{1,3,5,2}
// 注意,这段代码的精妙之处就在于不需要创建子数组。public static void insertionSort(int[] list){for (int i = 0; i < list.length; i++) {int cur = list[i];int j;// 注意,当i == j == 0时,for循环并不会执行,但是j = i仍然会发生,结果就是将第一个插入元素直接插入第一位。而这里并没有新数组,因此就是将list[0]的值赋给list[0]的无意义操作。for (j = i; j > 0 && list[j - 1] > cur; j--) {list[j] = list[j - 1];}list[j] = cur;}for (int x:list) {System.out.print(x + " ");}}public static void main(String[] args) {int[] a = {1, 3, 5, 7, 24, 73, 72, 2};insertionSort(a);}
public class BubbleSort {public static void main(String[] args) {int[] a = {6, 5, 7, 2, 9, 1, 0};boolean b = true;// 如果上次仍有排序,则继续循环,设置排序序号为falsefor (int j = 0; j < a.length && b; j++) {b = false;//注意每次循环次数减一for (int i = 1; i < a.length - j; i++) {if (a[i - 1] > a[i]) {// 交换元素int temp = a[i];a[i] = a[i - 1];a[i - 1] = temp;// 若本次仍存在冒泡,则继续大循环。// 否则默认终止循环。b = true;}}}for (int x : a) {System.out.print(x + " ");}}}
在最佳情况下,冒泡排序的时间为O(n),即一次全部冒泡成功。
最差情况为每次都要冒泡,为O(n^2)。
O(nlogn)
算法思路:
1.通过设计两个方法,一个是主排序方法,一个是单独的合并方法。在主方法中递归的调用分隔方法,直到分隔到底层,然后进行合并。
2.主方法中包含的方法:排序前半部分(递归1),排序后半部分(递归2),将两部分合并成一部分(合并方法)。
3.通过声明两个临时数组来存储数组的前半部分和后半部分。前半部分的数组长度直接通过list.length / 2,但是后面的要用原长度减去前面的长度,而不能直接除以二,否则将会造成数据丢失。如原长度为9,简单的除以二的话是4,两个4的话,最后一个数据就丢失了。
4.在合并方法中,传入三个数组,前半部分,后半部分,总数组。并分别设定三个初始为0的int的下标指向他们。通过while循环重复比较两个部分的数组,并将其中较小的那个元素复制到总数组中,同时该数组和总数组的下标都自增1。
5.当其中一个数组的下标达到尽头时,跳出循环,通过后面的两个while循环将剩下那个数组的剩余元素复制进去就好,因为每次要合并的两个小数组都是排好序的,因此剩下的这些元素直接复制进去是没有问题的。
代码:
import java.util.Arrays;public class MergeSort {public static void main(String[] args) {int[] a = {1, 3, 5, 2, 8};mergeSort(a);for (int x : a) {System.out.print(x + " ");}}public static void mergeSort(int[] list) {if (list.length > 1) { // 递归结束条件int[] firstHalf = new int[list.length / 2];int[] secondHalf = new int[list.length - firstHalf.length];// System里的数组复制方法,注意复制后半部分的时候,要从firstHalf.length开始复制(第二个参数),长度是secondHalf.length(最后一个参数)。System.arraycopy(list, 0, firstHalf, 0, firstHalf.length);System.arraycopy(list, firstHalf.length, secondHalf, 0, secondHalf.length);mergeSort(firstHalf);mergeSort(secondHalf);merge(firstHalf, secondHalf, list);}}public static void merge(int[] list1, int[] list2, int[] temp) {int index1 = 0;int index2 = 0;int index3 = 0;// 选取两个数组中较小的数放入最终数组,并在某个数组被读取完后停止。while (index1 < list1.length && index2 < list2.length) {if (list1[index1] < list2[index2])temp[index3++] = list1[index1++];elsetemp[index3++] = list2[index2++];}// 将剩下的数直接复制进最终数组。while (index1 < list1.length) {temp[index3++] = list1[index1++];}while (index2 < list2.length) {temp[index3++] = list2[index2++];}}}
package demo2;public class QuickSort {public static void quickSort(int[] list) {quickSort(list, 0, list.length - 1);}public static void quickSort(int[] list, int first, int last) {// 对于每个快速排序,last必须大于first,如果last=-1,就结束递归。if (last > first) {// 返回主元的位置,然后通过主元分割前后两端,并依次进行快速排序。int indexOfPivot = partition(list, first, last);quickSort(list, first, indexOfPivot - 1);quickSort(list, indexOfPivot + 1, last);}}// 返回主元的正确位置,并交换处于不正确位置的元素,使得主元的前面都小于主元,后面都大于主元。public static int partition(int[] list, int first, int last) {int pivot = list[first];int start = first++;int temp = 0;while (first < last) {// 当发现前后两个特例之后,将他们交换。// 如果只有小数列有特例,那么last会一直往前,越过大数列,停在小数列的最后一个位置。// 这种情况大数列本身就是排好序的,因此将小数列中的特例与小数列的最后一位交换。while (first < last && list[first] < pivot)first++;while (first < last && list[last] > pivot)last--;if (first < last) {temp = list[last];list[last] = list[first];list[first] = temp;}}// last的数小于等于pivot时停下。相当于将last放置在小数列的最后一个位置上,即大数列的第一个之前的那个位置。while (list[last] > pivot) {last--;}// 然后将last的数和第一个数(pivot)交换。list[start] = list[last];list[last] = pivot;// 返回last现在所在的位置,也就是主元现在的位置。return last;}public static void main(String[] args) {int[] a = {5, 2, 9, 3, 8, 4, 0, 1, 6, 7};quickSort(a);for (int x : a) {System.out.print(x + " ");}}}
O(nlogn)删除根元素
1.将最后一个元素复制到根元素位置,覆盖根元素。
2.将最后一个元素删除。
3.如果根元素小于两个子元素中较大的那个,将它们互换。
4.直到重新成为堆。
Heap类
package demo2;public class Heap<E extends Comparable<E>> {private java.util.ArrayList<E> list = new java.util.ArrayList<>();public Heap() {}public Heap(E[] objects) {for (int i = 0; i < objects.length; i++) {add(objects[i]);}}public void add(E newObject) {list.add(newObject);int cur = list.size() - 1;while (cur > 0) {int par = (cur - 1) / 2;if (list.get(par).compareTo(list.get(cur)) < 0) {E temp = list.get(cur);list.set(cur, list.get(par));list.set(par, temp);} elsebreak;// change par to cur.cur = par;}}public E remove() {if (list.size() == 0) return null;E removeObject = list.get(0);list.set(0, list.get(list.size() - 1));list.remove(list.size() - 1);int cur = 0;while (cur < list.size()) {int son1 = cur * 2 + 1;int son2 = cur * 2 + 2;// 左子节点要严格小于list才不会越界if (son1 >= list.size()) break;// 找到两个子节点中比较大的int max = son1;if (son2 < list.size()) {if (list.get(son1).compareTo(list.get(son2)) > 0)max = son1;elsemax = son2;}if (list.get(cur).compareTo(list.get(max)) < 0) {E temp = list.get(cur);list.set(cur, list.get(max));list.set(max, temp);cur = max;} elsebreak;}return removeObject;}public int getSize() {return list.size();}}
package demo2;public class HeapSort {public static <E extends Comparable<E>> void heapSort(E[] list) {// 通过list新建堆Heap<E> a = new Heap<>(list);// 注意,remove出来的是堆中最大的元素,因此要从后面开始遍历。for (int i = list.length - 1; i >= 0; i--) {list[i] = a.remove();}}public static void main(String[] args) {Integer[] a = {5, 2, 9, 3, 8, 4, 0, 1, 6, 7};heapSort(a);for (Integer x : a) {System.out.print(x + " ");}}}
MyList来声明相同的方法,然后让ArrayList和LinkedList接入接口后用不同的方式实现方法。MyAbstractList来添加size属性。MyAbstractList中的size被声明为protected,protected一般很少使用,但在这里很合适,因为它的子类可以访问大小,而其他包中的非子类并不能访问它。作为一个常用规则,可以将抽象类中的数据域声明为被保护的。


E[]数组来存储,存储的是引用。廖雪峰的官方网站:https://www.liaoxuefeng.com/wiki/1252599548343744/1264799402020448
class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。
TaskClass task = new TaskClass();// TaskClass类实现了Runnable接口Thread thread = new Thread(task);// 通过TaskClass创建一个线程thread.start();// 启动它
MyThread mythread = new MyThread();// Myshread类继承了Thread类mythread.start();// 直接启动子类就好
Thread.yield()方法用来暂时将时间让给其他线程。Thread.sleep()方法可以让线程暂时休眠几毫秒。注意:使用Thread.sleep()方法时,必须捕获InteruptedException。所以要将代码放到tryCatch块中。如果一个循环中调用了sleep方法,那就要将整个循环放入catch块中。Thread.join()方法可以让这个线程插队,其他线程会等待调用join的线程跑完再开始工作。setPriority()和getPriority()可以查看与设置优先级(0-10),优先级较高的线程会优先运行,如果一个高优先级的线程一直运行,会发生资源匮乏,因此,高优先级的线程必须定时的调用sleep()或yield()方法来让出资源。
new Thread(new Runnable(){}).start();// 填充run()方法new Thread(new Runnable(){@Overridepublic void run(){System.out.println("nihao");}}).start();// 可以使用Lambda表达式进一步简化,将new Runnable(){} 变成()-> {}// 并且不用写run()的方法头!new Thread(()->{System.out.println("nihao");}).start();
newFixedThreadPool(int n)用来创建一个最多运行n线程的线程池。如果一个线程60s没有被调用,则杀死他。newCachedThreadPool()创建一个灵活的线程池。
ExecutorService executor = Executors.newFixedThreadPool(3);// 如果设置为1,那么三个线程将串行执行。// 如果是newCachedThreadPool(),所有任务都并发执行。executor.execute(new PrintChar('a', 100));// +execute(Runnable object):voidexecutor.execute(new PrintChar('b', 100));executor.execute(new PrintNum(100));executor.shutdown();
synchronized(expr){ // expr必须是一个对象的引用//...}synchronized(account){account.toString();}将synchronized后面的括号中填上this,就可以锁定当前对象或者当前类。

private static Lock lock = new ReentrantLock();lock.lock();try{}catch{}finally{lock.unlock();}尽量把锁的释放放在finally里,这样可以确保锁被释放。

例如,我们想通过两个线程,一个提款,另一个存款,在单独行动的时候另一个都不能打扰,而在某些情况下又想把锁移交过去,比如提款余额不足的时候就调用存款线程,先存进去,然后再调用取款线程,尝试取款。

代码实现
private static Lock lock = new ReentrantLock();private static Condition newDeposit = lock.newCondition();









https://www.cnblogs.com/cjsblog/p/9078341.html

