javase基础学习

JAVA基础语法

基础语法

位运算

& | ^ ~ << >>

流程控制学习

Scanner

Scanner scanner = new Scanner(System.in);

String str = scanner.next();//输入时遇到空格结束

String str=scanner.nextlLine();//输入时enter结束

image-20210310203843522

判断输入是否正确

if(scanner.hasNextInt()){输入}`

`else error;

判断是不是输入整型

增强for循环

image-20210311133906902

int [][] m = {{1,2,3,4,5},{1,2,3,4,5}};
for(int[] x:m)
for(int y:x)
System.out.println(y);

方法详解

方法定义

image-20210311145653472

方法重载

方法名字一样 参数列表(必须)不同和返回类型不同

public int  max(int a,int b)

{

}

public double max(double a ,double b)

{

}

 

可变参数

public static void test(int ...i){
System.out.println(i[0]);
}

main(){
test(1,2,3,4);
}

递归

image-20210311153258625

阶乘

public static int f(int n)

{

if(n==1) return 1;

else return n*f(n-1);

}

 

数组

数组声明和创建

int[] num1;//

num = new int[10];

数组初始化

1.动态初始化(包含默认初始化)

int[] num1;

num = new int[10];

num[0]=1;//剩下的数组默认为0(即为默认初始化)

2.静态初始化

int[] num ={1,2,3,4,5};

数组使用

数组反转

public static int[] reverse(int [] m)
{
int[] res = new int[m.length];
for(int i=0,j=m.length-1;i<m.length;i++,j--)
{
res[i] = m[j];
}
return res;
}

 

二维数组

int a = {{1,2,3},{4,5,6}};

Arrays类

import java.util.Arrays

int[] a={1,2,3,45,6,7},

System.out.println(Arrays.toString(a));//打印数组元素

//打印结果[1, 2, 3, 45, 6, 7]
//数组排序 void类型
Arrays.sort(b);
for(int x: b)
System.out.print(x);

冒泡排序

boolean用来判断数组是不是已经排序好了 避免多有的排序

    boolean flag=false;
for (int i= 0; i < a.length -1;i++)
{

for(int j=0;j<a.length-i-1 ;j++)
{
if(a[j+1]<a[j])
{
int term = a[j];
a[j]= a[j+1];
a[j+1] = term;
flag = true;

}
}
if(flag==false) break;
}

稀疏数组

image-20210312151207038

代码见demo5

面向对象

概念

本质:

以类的方式组织代码,以对象的组织(封装)数据

特性:

继承、封装、多态

静态和非静态方法的区别

静态:

public class Student{

public static void say();//静态

public void say();//非静态

}

public static void main(String[] args)
{
静态调用:
Student.say();
//非静态调用
Student student = new Student;
student.say();
}

 

静态方达不能调用非静态方达

值传递和引用传递

  //值传递和引用传递

public class demo01 {
  public static void main(String[] args) {
      int a = 0;
      turn(a);
      System.out.println(a);//值传递a的值不变

      Person person = new Person();
      System.out.println(person.name);//输出是空
      change(person);
      System.out.println(person.name);输出“123";
       
  }
   
  public static void turn(int c ){
      c = 10;
       
  }
  public static void change(Person person)
  {
      person.name = "123";
  }
  public static class Person{
      String name;//null
  }
}

 

类和对象的创建

创建和初始化对象

new

image-20210315201512541

 

构造器

和类名相同 没有返回值

class Person()

{

}

一个类会自动隐士构造一个无参构造 如果想使用有参构造 就必须显示定义无参构造

一个类即使什么都不写也会存在一个构造方法

  //一个类即使什么都不写也会存在一个方法
  //无参构造器
  //1.使用new关键字本质在调用构造器
  //2.用于初始化值
  public Person(){

  }


  //有参构造器
  public Person(String name)
  {
      this.name = name;
  }

 

封装详解

封装的概念

封装:数据的隐藏

程序追求 高内聚低耦合

image-20210316161601474

inde快捷键 ALT + INS

 

 

继承

extends

image-20210320210136978

 

 

Super详解

 

image-20210320210256761

方法重写

image-20210320210341730

 

 

多态

动态编译

动态是方法的多态

 

 

Person s1 = new Student();

对象能执行哪写方法看左边类型 和右边关系不大

 

image-20210320212800192

1.多态是方法的多态 不是属性的多态

2.父类和子类 有联系

3,存在条件 继承关系 子类需要重写 父类的引用指向子类对象

static、final 、private方法不能重写

Static 关键字

 

抽象类

关键字abstract

抽象类的所有方法必须要继承的子类实现 除非子类也是abstract

 

特点:

1.不能用来new 只能靠子类实现

2.抽象类 里面可以写普通方法 抽象方法必须在抽象类里面

image-20210320215527051

 

接口的定义与实现

关键词 interface

实现接口: implements

demo09jiekou

image-20210320234039116

 

 

内部类

 

 

异常处理

Exception

捕获和抛出异常

关键字:try catch finally throw throws

image-20210321143450694

 

image-20210321143638047

 

抛出异常快捷键:

cTRL +ALT+ T

try {
  System.out.println(b/a);
} catch (Exception e) {
  e.printStackTrace();//打印错误栈信息
}

image-20210321144346734

//throw 和 throws 的区别

 

 

自定义异常

 

集合框架详解

基本概念

集合:对象的容器,实现对多个对象进行操作的常用方法

与数组区别:

1.长度不固定

2.数组可以储存基本类型和引用类型 集合只能储存引用类型

位置:java.util.*

Collection体系集合

image-20210321190400475

Collection 使用

方法:

image-20210321190537199

 Collection collection  = new ArrayList();//Arraylist 有顺序的
//添加元素
      collection.add("苹果");
      collection.add("香蕉");
      collection.add("橘子");
      System.out.println(collection.size());
      System.out.println(collection);

输出结果

image-20210321213541626

删除操作:

collection.remove("香蕉");
System.out.println(collection);

image-20210321213724022

清空:

collection.clear();

遍历元素

方法1:增强for

for (Object object: collection) {
  System.out.println(object);
}

方法2:迭代器

Iterator

//迭代过程不能使用collection改变元素

Iterator it = collection.iterator();
while(it.hasNext())
{
  String s = (String)it.next();
  System.out.println(s);
}

判断

1.判断元素是否存在

System.out.println(collection.contains("苹果"));

输出true

 

collection与对象 的使用

//新建collection 对象
Collection collection = new ArrayList();
Student s1 = new Student("张三",11);
Student s2 = new Student("里斯",12);
Student s3 = new Student("王五",13);
//1.添加数据
collection.add(s1);
collection.add(s2);
collection.add(s3);
System.out.println(collection.size());
System.out.println(collection.toString());
//2.删除
collection.remove(s1);
//3.清除
//collection.clear();
//4.遍历

 

List

特点: 有序 有下标 元素可以重复

方法:image-20210323205121888

使用方法

/创建集合
  List list =new ArrayList<>();
  //添加元素
  list.add("小米");
  list.add("华为");
  list.add("oppo");
  System.out.println(list.size());
  //2.删除元素
  // list.remove("oppo");
  // list.remove(0);
  //3.遍历
  for (int i = 0; i < list.size(); i++) {
      System.out.println(list.get(i));
  }
  //增强for
  for (Object o : list) {
      System.out.println(o);

  }
  System.out.println("++++++++");
  //迭代器
  Iterator it = list.iterator();
  while(it.hasNext())
      System.out.println(it.next());
  System.out.println("___________________列表迭代器从前往后");
  //列表迭代器 允许按照任一方向遍历 还可以添加删除修改

  ListIterator it0 =list.listIterator();
  while(it0.hasNext())
  {
      System.out.println(it0.nextIndex()+":"+it0.next());

  }
  //"从后往前"
  System.out.println("___________________列表迭代器从h后往前");
  while(it0.hasPrevious())
  {
      System.out.println(it0.previousIndex()+":"+it0.previous());
  }

  //4.判断是否存在 是否为空
  System.out.println(list.contains("小莫"));
  System.out.println(list.empty());

  //获取元素位置
  System.out.println(list.indexof("华为") );
}

list将对象存入之后如何调对象的值

((Student)list.get(i)).getname();

student对象是student类型 而list对象是Object类型 所有需要强制类型转换

list中数据的比较:

lsit.get(i).equals(list.get(j));

list的实现类:

1.Arraylist

数组 查找 遍历速度快 增加删除速度慢

 //1.增加元素
      Student s1= new Student("杨哥",20);
      Student s2= new Student("帅哥",20);
      Student s3= new Student("阳哥",20);
      Student s4= new Student("老哥",20);


      arraylist.add(s1);
      arraylist.add(s2);
      arraylist.add(s3);
      System.out.println("元素个数"+arraylist.size());
      //2.删除元素
      // arraylist.remove(s1);
      // System.out.println("删除之后元素个数"+arraylist.size());
      //arraylist.remove(new Student("帅哥",20));!!!重写了Student中的equals函数
      // System.out.println("删除之后元素个数"+arraylist.size());



      //3.遍历元素【红重点】
      for (Object o:arraylist) {
          System.out.println(o.toString());

      }
      //3.1使用迭代器
      Iterator it = arraylist.iterator();
      while(it.hasNext())
      {
          Student s =(Student)it.next();
          System.out.println(s.toString());
      }
      //3.2列表迭代器
      //同list


      //4.判断
      System.out.println(arraylist.contains(s1));
      System.out.println(arraylist.isEmpty());
      //5.查找
      System.out.println(arraylist.indexOf(s1));

  }
}

2.vector

3.linklist

泛型

语法<T,....> T为类型占位符,表示一种引用类型

泛型类

public class MyGenerics<T>{
  //使用泛型
  //1.创建变量

  T t;//不能new T

  //2.添加方法
  public void show(T t){
      System.out.println(t);
  }
  //3.泛型作为方法返回值
  public T get(){
      return t;
  }
}
public class testGenerics {
  public static void main(String[] args) {
      //使用泛型类创建对象
      MyGenerics<String> mygenerics= new MyGenerics<>();
      mygenerics.t="hello";
      mygenerics.show("大家好");
      String string = mygenerics.get();
      System.out.println(string);
      MyGenerics<Integer> mygenerics2 = new MyGenerics<>();
      mygenerics2.t=2;
      Integer in = mygenerics2.get();
      mygenerics2.show(200);
      System.out.println(in);
       


  }
}

 

泛型接口

public interface MyInterface<T>{
  String name = "张三";
  T serve(T t);


}

 

 

class  MyInterfaceImpl implements  MyInterface<String>{

  @Override
  public String serve(String s) {
      System.out.println(s);

      return s;
  }
}

泛型方法

public class GenericsMethod {
 
  public <T> T show(T t)
  {
      T t2;
      return t;
  }

}

//泛型方法
      GenericsMethod genericsMethod = new GenericsMethod();
      genericsMethod.show(" ");
      genericsMethod.show(200);//由传递的数据决定类型
      genericsMethod.show(3.14);

 

泛型的好处

提高代码的重用性

防止类型转换异常 提高代码的安全性

泛型集合

ArrayList <Student> arrayList2 = new ArrayList<Student>();
Student s1= new Student("name",20);
Student s2= new Student("name2",20);
arrayList2.add(s1);
arrayList2.add(s2);
for(Student s : arrayList2)
  System.out.println(s);
System.out.println(s1.getName());

 

set集合

特点:元素不可重复 无序无下标

方法:全部继承自Collection中的方法

接口

ublic static void main(String[] args) {
  Set<String> set = new HashSet<>();
  //1.添加
  set.add("苹果");
  set.add("香蕉");
  set.add("橘子");
  System.out.println(set.size());
  set.add("橘子");
  System.out.println(set.size());//添加相同元素后没有加进去

  //2.删除
  set.remove("橘子");
  System.out.println("删除后元素个数"+set.size());//添加相同元素后没有加进去

  //3.遍历

  //3.1 z增强for
  System.out.println("---------------------增强for输出");
  for (String s:set) {
      System.out.println(s);

  }

  //3.2迭代器
  System.out.println("---------------------迭代器输出");
  Iterator<String> it = set.iterator();
  while(it.hasNext())
  {
      System.out.println(it.next());
  }
  //4.判断
  //是否为空
  System.out.println(set.isEmpty());
  //判断元素
  System.out.println(set.contains("苹果"));

 

HashSet 【重点】

 

存储方式:哈希表

存储过程:

(1)根据hashcode计算保存位置,如果位置为空则直接报存不为空则执行第二部

(2)再执行equals方法:如果equals为true,则认为是重复,否则形成链表

image-20210329203006460

 

 

Person p1 = new Person("老王",25);
Person p2= new Person("老李",28);
Person p3 = new Person("老张",23);

HashSet<Person> hashset2 = new HashSet<Person>();
hashset2.add(p1);
hashset2.add(p2);
hashset2.add(p3);
System.out.println(hashset2);//可以看到 与顺序无关
hashset2.add(new Person("老王",25));//需要重写HashCode和equals才能判断是重复的 重写之前加进去了 重写之后就加不进去了

Person对象重写:

@Override
public int hashCode()
{
  int n1=this.name.hashCode();
  int n2=this.age;
  return n1+n2;
}

@Override
public boolean equals(Object obj) {
  if(this == obj) return true;
  if(obj==null) return false;
  if(obj instanceof Person)
  {
      Person p =(Person) obj;
      if(this.name.equals(p.getName())&&this.age==p.getAge())
      {
          return true;
      }
  }
  return false;
}

hashcode 中的31的作用

(1)31是质数 减少散列冲突

(2)31提高执行 效率 是(i<<5) -i 左移五位

 

TreeSet

基于排序 实现元素不重复

实现了SortedSet接口,对集合元素自行排序

元素对象的类型必须实现Comparable接口 ,指定排序规则

通过CompareTo方法确定是否为重复元素

实现接口Comparable

Comparable接口
@Override
public int compareTo(Person o) {
  int n1 = this.getName().compareTo(o.getName());
  int n2 = this.age - o.getAge();

  return n1==0?n2:n1;//x先比姓名再比年龄
}
comparator接口

image-20210329233903194

另外定义比较规则

 

/*
*实现案例 通过treeSet方法按照字符串长度比较字符串
*/
public class demo02 {
  public static void main(String[] args) {
      TreeSet<String> tree =new TreeSet<>(new Comparator<String>() {
          @Override
          public int compare(String o1, String o2) {
              int n1=o1.length()-o2.length();
              int n2=o1.compareTo(o2);
              return n1==0? n2:n1;
          }
      });
      tree.add("sada");
      tree.add("sdadasda");
      tree.add("sdada");
      tree.add("dasdadasda");
      tree.add("dsada");
      System.out.println(tree);
  }
}

Map集合

 

image-20210330153546866

 

Map接口特点:

1.用于存储任意键值对(Key-value)

2.键:无序、无下标、不允许重复

3.值:无序、无下标、允许重复

Map父接口:

特点:存储一对数据(Key-Value)

方法:

V put(K key , V value)//将对象存入到集合中,关联键值,key重复则覆盖原值

Object get(Object key)//根据键获取对应的值

KeySet<K>//返回所有的key

Collectoon<V> values()//返回包含所有值的Collection集合

Set<Map,Entry<K,V>>//键值匹配Set集合

接口使用

//创建MAp集合
Map<String,String> map =new HashMap<>() ;
//添加元素
map.put("uk","英国");
map.put("USA","美国");
map.put("CHN","中国");

//删除
map.remove("uk");//删除的时候删键值就行

System.out.println("元素个数"+ map.size());
System.out.println(map.toString());

//遍历
//3.1使用KeySet
System.out.println("使用KeySet遍历————————————————————");
//Set<String > keyset = map.keySet();
for(String key:map.keySet())
{
  System.out.println(key+"   "+map.get(key));//map.get(key)获取值

}
//3.2使用entrySet方法 效率比KeySet高
//Set<Map.Entry<String,String>> entries= map.entrySet();
for(Map.Entry<String,String> entry : map.entrySet())
{
  System.out.println(entry.getKey()+"   "+entry.getValue());
}
//4.判断
      System.out.println(map.containsKey("CHN"));
      System.out.println(map.containsValue("中国"));

image-20210330171334247

 

Map集合的实现类:

HashMap[重点]

线程不安全 运行效率快;允许使用null作为key或是value

 

image-20210330175449792

 

HashTable

 

TreeMap

可以对key自动排序

存储结构:红黑树

 

重写Comparable

public class Person  implements  Comparable<Person>

@Override
  public int compareTo(Person o) {
      int n1=this.name.compareTo(o.getName());


      return n1;

Collection工具类

方法:

image-20210330210030586

重要!!!

 //sort排序
  Collections.sort(list);
  System.out.println(list);

  //二分查找
  int i = Collections.binarySearch(list,16);//返回小标
  System.out.println(i);

  //copy
  List<Integer> list2 = new ArrayList<>();
  for (int k = 0; k < list.size(); k++) {
      list2.add(0);

  }
  Collections.copy(list2,list);//必须要集合大小一样才行
  System.out.println(list2);
  //reverse 反转

  Collections.reverse(list2);
  System.out.println(list2);

  //shuffle 打乱
  Collections.shuffle(list2);
  System.out.println(list2);

  //list转数组 和数组转list
  Integer[] a = list.toArray(new Integer[0]);
  System.out.println(a.length);
  System.out.println(Arrays.toString(a));//直接输出数组

  //数组变集合
  String[] name={"张三","里斯哦","saa"};
  List<String > name2 = Arrays.asList(name);
  //这个集合是个受限集合 不能删除添加 长度是固定的

  int[]b ={1,2,3,4};
  List<int []> list3 = Arrays.asList(b);


}

 

集合总结

image-20210330212531662

 

 

 

 

 

 

 

 

 

IO流(还没总结)

JavaFX(还没总结)

按钮事件:

.setOnMouseClicked(new EventHandler<MouseEvent>() {
  public void handle(MouseEvent event) {});

 

 

list.get(i)  获取第i个元素  但是是object类型  

 

多线程详解

1.线程简介:

多线程

操作系统中运行的程序为进程,一个进程可以有多个线程

Process 进程 Thread线程

程序:

进程:

线程:

image-20210331201504990

image-20210331201606167

2.线程创建

Thread (class) 继承Thread类(重点)

Runnable(接口) 实现Runnable接口(重点)

Callable 实现Callable接口(了解)

Thread

不建议使用 避免OOP单继承局限性

自定义线程继承Thread

重写run方法 编写线程执行体

创建线程对象调用start方法

/*
*自定义线程继承Thread   重写run方法 编写线程执行体
*创建线程对象调用start方法开启线程
* 总结:线程开启不一定立即执行 由cpu调度
*/
public class TestThread extends Thread {

  public void run()
  {
      for (int i = 0; i < 200; i++) {
          System.out.println("我在看代码"+i);
      }

      //run方法线程体
  }

  public static void main(String[] args) {
      //mian线程 主线程

      //创建一个线程对象
      TestThread testthread = new TestThread();

      //调用start()方法开启
      testthread.start();
      //

      for (int i = 0; i < 1000; i++) {
          System.out.println("我在学习多线程"+ i);
      }
  }
}

 

Runnable

推荐使用 灵活方便 方便同一个对象被多个线程使用

!!!

 TestThread3 testthread3 = new TestThread3();
      //创建线程对象通过线程对象开启线程
      new Thread(testthread3).start();

实现Runnable方法 执行线程需要丢入Runnable接口实现类 重写run方法

public class TestThread3  implements  Runnable{
  @Override
  public void run()
  {
      for (int i = 0; i < 200; i++) {
          System.out.println("我在看代码"+i);
      }

      //run方法线程体
  }

  public static void main(String[] args) {


      //创建一个线程对象
      TestThread3 testthread3 = new TestThread3();
      //创建线程对象通过线程对象开启线程
      new Thread(testthread3).start();




      for (int i = 0; i < 1000; i++) {
          System.out.println("我在学习多线程"+ i);
      }
  }

lambda表达式:

new Thread(()->sout("我爱你")).strat;

Caliable接口

了解即可

 

3.初识并发问题

买火车票案例

/*
*多线线程同时操作同一个对象
*买火车票的例子
* 发现问题:多个线程操作同一个资源时 出现资源紊乱
*/
public class TestThread4 implements Runnable {
  //
  private int ticketNum = 10;

  @Override
  public void run() {
      while(true)
      {
          if(ticketNum<=0)
          {break;}

          //模拟延时
          try{
              Thread.sleep(200);
          }catch(InterruptedException e)
          {
              e.printStackTrace();
          }



          System.out.println( Thread.currentThread().getName()+ "拿到了第"+ticketNum--+"张票");
      }

  }

  public static void main(String[] args) {

      TestThread4 ticks = new TestThread4();
      new Thread(ticks,"小明").start();
      new Thread(ticks,"老师").start();
      new Thread(ticks,"黄牛").start();


  }
}

输出:(同时出现了7)

老师拿到了第9张票 小明拿到了第8张票 黄牛拿到了第10张票 小明拿到了第7张票 老师拿到了第7张票 黄牛拿到了第6张票 老师拿到了第5张票 黄牛拿到了第4张票 小明拿到了第3张票 老师拿到了第2张票 黄牛拿到了第1张票 小明拿到了第0张票

Process finished with exit code 0

 

 

龟兔赛跑案例

/*
*模拟归龟兔赛跑
*/
public class Race implements Runnable {
  private static String winnner;
  public void run()
  {
      for (int i = 0; i <= 100; i++) {
          //模拟兔子休息
          if(Thread.currentThread().getName().equals("兔子")&&i%10==0)
          {
              try {
                  Thread.sleep(1);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }

          //判断比赛是否结束
          boolean flag = gameover(i);
          if(flag){
              break;
          }
          System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
      }



  }
  private boolean gameover( int steps)
  {
      if(winnner!=null) return true;
      if(steps>=100){
          winnner = Thread.currentThread().getName();
          System.out.println("Winner is" + winnner);
          return true;

      }
      return false;
  }

  public static void main(String[] args) {
      Race race =new Race();
        new Thread(race,"兔子").start();
      new Thread(race,"乌龟").start();
  }
}

 

4.静态代理

/*
*
* 静态代理模式
* 真实对象和代理对象都要实现同一个接口
* 代理对象必须代理真实对象
*
*/
public class StaticProxy {
  public static void main(String[] args) {
      WeddingCompany weddingCompany = new WeddingCompany( new You());
      weddingCompany.happymarry();
  }
}

interface Marry{

  void happymarry();
}

//真是角色 你去结婚
class You implements Marry{
  @Override
  public void happymarry()
      {
          System.out.println("结婚了真开心");
      }

}

//代理角色 帮助你结婚
class WeddingCompany implements Marry{

  private Marry target;

  public WeddingCompany(Marry target)
  {
      this.target = target;
  }
  @Override
  public void happymarry()
  {
      before();
      this.target.happymarry();
      after();
  }
  public void before(){
      System.out.println("结婚前 布置现场");

  }
  public void after()
  {
      System.out.println("结婚之后收尾款");
  }

 

5.lambad表达式

因为Runnable只有一个run方法

image-20210401220213335

interface TLike
{
  void lambda();
}


psvm
//6.应lambda简化
      tlike = () ->{
          System.out.println("l like lambad5 lambda表达式");
      };
      tlike.lambda();

 

6.线程状态

创建状态

就绪状态

阻塞状态

运行状态

结束状态

image-20210403164343076

 

线程方法:

image-20210403165209315

停止线程

image-20210403221235648

线程休眠

image-20210403221315387

获取系统当前时间

while(true){
  try {
      Thread.sleep(1000);
      Date StartTime = new Date(System.currentTimeMillis());//获取系统当前时间
      System.out.println(new SimpleDateFormat("HH:mm:ss").format(StartTime));
  } catch (InterruptedException e) {
      e.printStackTrace();
  }
}

线程礼让yield

 

image-20210403223758495

public class YieldTest {
  public static void main(String[] args) {
      MyYeild yt =new MyYeild();
      new Thread(yt,"a").start();
      new Thread(yt,"b").start();
  }

}
class MyYeild implements Runnable{

  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName()+"开始执行");
      Thread.yield();
      System.out.println(Thread.currentThread().getName()+"执行结束");
  }
}

线程强行执行Join

image-20210403233654984

public class JoinTest  implements Runnable{
  @Override
  public void run() {
      for (int i = 0; i < 1000; i++) {
          System.out.println("vip用户来了" +i);
      }
  }

  public static void main(String[] args) throws InterruptedException {

      JoinTest joinTest = new JoinTest();
        Thread thread = new Thread(joinTest);
        thread.start();

        //主线程
      for (int i = 0; i < 1000; i++) {
          if(i==200) {
              thread.join();//被插队
          }
          System.out.println("main"+i);
      }
  }
}

 

观测线程状态

image-20210405200412010

 

/*
*观察线程状态
*
*/
public class StateTest {
  public static void main(String[] args) throws InterruptedException {

      Thread thread = new Thread(()-> {
          for (int i = 0; i < 5; i++) {
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
          System.out.println("/////////");
      });


      //观察状态
      Thread.State state = thread.getState();
      System.out.println(state);

      //观察启动后
      thread.start();//启动线程
      state = thread.getState();
      System.out.println(state);//Run

      while(state!=Thread.State.TERMINATED)
      {
          Thread.sleep(100);
          state = thread.getState();
          System.out.println(state);

      }
  }
}

线程优先级

image-20210405204703768

public class PriorityTest  {
  public static void main(String[] args) {
      //主线程默认优先级
      System.out.println(Thread.currentThread().getName()+ "---> " + Thread.currentThread().getPriority());

      MyPriority mypriorty = new MyPriority();

      Thread t1 = new Thread(mypriorty);
      Thread t2 = new Thread(mypriorty);
      Thread t3 = new Thread(mypriorty);
      Thread t4 = new Thread(mypriorty);
      Thread t5 = new Thread(mypriorty);

      //先设置优先级再启动
      t1.start();

      t2.setPriority(1);
      t2.start();

      t3.setPriority(4);
      t3.start();

      t4.setPriority(Thread.MAX_PRIORITY);//MAx.PRIORITY
      t4.start();

      t5.setPriority(8);
      t5.start();

  }
}

class MyPriority implements Runnable{


  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName()+ "---> " + Thread.currentThread().getPriority());
       
  }
}

 

守护(deamon)线程

image-20210405210753565

package JavaStudy.Thread.state;
/*
测试守护线程
当用户线程结束后 守护线程也停止了
*/
public class DaemonTest {
  public static void main(String[] args) {
      God god = new God();
      You you = new You();

      Thread thread =new Thread(god);
      thread.setDaemon(true);//默认是false

      thread.start();//上帝守护启动

      new Thread(you).start();//线程 你启动

  }
}

//
class God implements Runnable{

  @Override
  public void run() {
      while (true)
      {
          System.out.println("上帝保佑你");
      }

  }
}

//你
class You implements Runnable{
  @Override
  public void run(){
      for (int i = 0; i < 36500; i++) {
          System.out.println("你一生都在开心得活着");
      }
      System.out.println("------doodbye");
  }
}

7.线程同步机制

多个线程操作同一个资源

 

并发:

同一个对象多个线程共同操作

 

线程同步

image-20210405212321042

线程同步条件: 队列加锁

锁机制 synchronized

image-20210405212708867

同步方法

image-20210406170058104

 

 

image-20210406170332394

 

银行取钱案例
//不安全的取钱
//两个人去银行取钱
//用synchronized同步块锁Account对象

public class USafeBank {
  public static void main(String[] args) {
      Account account = new Account(100,"结婚基金");

      Drawing you = new Drawing(account,50,"你");
      Drawing grilf = new Drawing(account,100,"妻子");

      you.start();
      grilf.start();
  }

}
//账户
class Account {
  int money;
  String name;

  public Account(int money, String name) {
      this.money = money;
      this.name = name;
  }
}

//银行取款
class Drawing extends Thread{
  Account account;//账户
  //取了多少钱
  int drawingMoney ;
  //现在手里有多少钱
  int NowMoney;

  public Drawing(Account account,int drawingMoney,String name)
  {
      super(name);
      this.account = account;
      this.drawingMoney = drawingMoney;

  }
  //取钱
  //synchornized默认锁的是this
  @Override
  public void run(){
   
  //锁的对象是锁被更改的对象
      synchronized (account)
      {
          //判断有没有钱
          if(account.money - drawingMoney< 0)
          {
              System.out.println(Thread.currentThread().getName() + " 钱不够,取不了");
              return;
          }
          //sleep放大问题发生
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }

          //卡内余额 = 余额-你取的钱
          account.money = account.money - drawingMoney;
          //你手里的钱
          NowMoney = NowMoney + drawingMoney;

          System.out.println(account.name + "余额为: " +account.money);
          System.out.println(this.getName()+ "手里的钱" + NowMoney);//this.getName() = Thread.currentThread().get name()
      }

  }
}

 

2.list案例
//线程不安全的集合
//线程可能添加到了同一个位置
public class UsafeList {
  public static void main(String[] args) throws InterruptedException {
      List<String> list = new ArrayList<String>();
      for (int i = 0; i < 10000; i++) {
          new Thread(()->{
              synchronized(list) {
                  list.add(Thread.currentThread().getName());
              }}).start();

      }
      Thread.sleep(3000);
      System.out.println(list.size());
  }
}

 

死锁

image-20210406210124685

 

image-20210406212932819

 

Lock锁

image-20210406213037329

 

ReentranLock可重复锁

 

class TestLock2 implements Runnable{

  int ticknum = 10;

  //定义Locks锁
  private final ReentrantLock lock = new ReentrantLock();

  @Override
  public void run() {
      while(true)
      {

          try{
              lock.lock();//加锁
              if(ticknum>0)
              {
                  System.out.println(Thread.currentThread().getName() + ticknum--);
                  try {
                      Thread.sleep(100);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              else {
                  break;
              }
          }finally {
              lock.unlock();//解锁
          }


      }
  }

image-20210406214221977

image-20210406214248709

 

 

8.线程协作

生产者消费者问题

 

image-20210406215407317

解决生产者消费者问题方法1:管程法

image-20210406215621156

 

package JavaStudy.Thread.gaoji;

//生产者消费者模型 利用缓冲区解决:管程法

//生产者、消费者、缓冲区

public class TestPC {
  public static void main(String[] args) {
      SynContains container = new SynContains();

      new Productor(container).start();
      new Consunmer(container).start();
  }
}

//生产者
class Productor extends Thread{
  SynContains container;

  public Productor(SynContains container){
      this.container = container;
  }
  @Override
  public void run(){
      for (int i = 0; i < 100; i++) {

          container.push(new Chicken(i));
          System.out.println("生产了" + i+"只鸡 ");
      }
  }

}

//消费者
class Consunmer extends Thread{

  SynContains container;

  public Consunmer(SynContains container){
      this.container = container;
  }
  public void run(){
      for (int i = 0; i < 100; i++) {
          System.out.println("消费了---->" + container.pop().id+"只鸡 ");
      }
  }
}

//产品
class Chicken{
  int id;

  public Chicken(int id) {
      this.id = id;
  }
}

//缓冲区
class SynContains{
  //需要一个容器大小
  Chicken[] chickens = new Chicken[10];

  //容器计数器
  int count = 0;

  //生产者放入产品
  public synchronized void push(Chicken chicken){
      //如果容器满了 就等待消费者消费 没有满就丢入
      if(count == chickens.length){
        //通知消费者消费 生产等待
          try {
              this.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }

      }
      //如果没有满 放入产品
      chickens[count]=chicken;
      count++;

      //可以通知消费者消费
      this.notify();
  }

  //消费者消费产品
  public synchronized Chicken pop(){
      //判断能否消费
      if(count == 0)
      {
          try {
              this.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          //等待生产者生产,消费者等待

      }
      count--;
      Chicken chicken = chickens[count];
      //吃完了通知生产者生产
      this.notify();
      return chicken;
  }

}

 

 

 

解决生产者消费者问题方法2:x信号灯法

package JavaStudy.Thread.gaoji;

//测试生产者消费者问题模型 : 信号灯法 通过标志位解决


public class TestPc2 {
  public static void main(String[] args) {
      TV tv =new TV();

      new Player(tv).start();
      new Watcher(tv).start();
  }
}

//生产者--> 演员
class Player extends Thread{
  TV tv;
  public Player(TV tv){
      this.tv=tv;
  }

  @Override
  public void run() {
      for (int i = 0; i < 20; i++) {
          if(i%2==0){
                  this.tv.play("快乐大本营播放中");
          }
          else {

                  this.tv.play("抖音记录美好生活");

          }
      }
  }
}

//消费者:观众
class Watcher extends Thread{
  TV tv;
  public Watcher(TV tv){
      this.tv=tv;}

      @Override
      public void run(){
          for (int i = 0; i < 20; i++) {
                  tv.watch();

          }
      }



}

//产品 : 节目
class TV{
  //演员表演的时候 观众等待
  //观众看的时候 演员等待
  String voice;
  boolean flag = true;

  //表演
  public synchronized void play( String voice) {
      if(!flag)
      {
          try {
              this.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      System.out.println("演员表演了" + voice);
      //通知观众观看
      this.notifyAll();
      this.voice = voice;

      this.flag = !this.flag;
  }

  //观看
  public synchronized void watch(){
      if(this.flag)
      {
          try {
              this.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      System.out.println("观众观看了" + voice);
      //通知演员表演
      this.notifyAll();
      this.flag = !this.flag;
  }
}

 

 

线程池

image-20210406230500833

image-20210406233428109

 

package JavaStudy.Thread.gaoji;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//测试线程池
public class TestPool {
  public static void main(String[] args) {
      //1。创建线程池

      ExecutorService sercive = Executors.newFixedThreadPool(10);
      //newFixedThreadPool()参输为线程大小

      sercive.execute(new MyThread());
      sercive.execute(new MyThread());
      sercive.execute(new MyThread());

      //2.关闭
      sercive.shutdown();
  }
}

class MyThread implements Runnable{

  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName());
  }
}

 

9.总结

 

 

 

 

网络编程(未总结)

 

GUI(未总结)

 

注解和反射

Annotation注解

 

注解入门

image-20210407150234748

内置注解

@Override 重写

@Deprecated 不建议使用 有危险或者存在更好的使用

@SuppressWarnings

image-20210407151457147

元注解

mate-Annotation

 

@Target

@Retention

image-20210407151613916

自定义注解

@interface

package JavaStudy.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//自定义注解
public class demo03 {
  @MyAnnotation2(name = " 阳",schools = {"西北大学,西工大"}) //注解可以显示赋值 如果没有默认值 必须赋值
  public void test(){ }

  @MyAnnotation3(" ")//只有一个注解时 可以直接赋值
  public void test2(){ }
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
  //注解的参数 : 参输类型 + 参输名 + ()
  String name() default" ";//default ""默认成空
  int age()default 0;
  int id()default -1;//如果-1 代表不存在

  String[] schools()default {"北大","清华"} ;//默认为清华北大
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
  String value();
}

 

Reflection反射机制

image-20210407160418109

Java反射机制概述

image-20210407160648391

优缺点;

优点:可以实现动态创建对象和编译,体现出很大的灵活性

缺点:对性能有影响 使用反射基本上是一种解释操作,这类操作慢于直接执行相同的操作

Class类

image-20210407162343341

image-20210407162533311

Class类常用方法

image-20210407162720725

获取Class类的实例

image-20210407162924822

package JavaStudy.Reflection;

import java.security.spec.RSAOtherPrimeInfo;

//测试class类的创建方式有哪些
public class test02 {
  public static void main(String[] args) throws ClassNotFoundException {
      Person person = new Student();
      System.out.println("这个人是" + person.name);

      //方式一:通过对象获得
      Class c1 = person.getClass();
      System.out.println(c1.hashCode());

      //方式2forname获得
      Class c2 = Class.forName("JavaStudy.Reflection.Student");
      System.out.println(c2.hashCode());

      //方式三 : 通过类名.class
      Class c3 = Student.class;
      System.out.println(c3.hashCode());

      //方式四:基本内置类型的包装类都有一个type属性
      Class   c4= Integer.TYPE;//int 类
      System.out.println(c4);

      //获得父类类型
      Class c5 = c1.getSuperclass();
      System.out.println(c5);
  }

}


class Person{
  public String name;

  public Person() {
  }

  public Person(String name) {
      this.name = name;
  }

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  @Override
  public String toString() {
      return super.toString();
  }
}

class Student extends Person{
  public Student(){
      this.name = "学生";
  }
}

class Teacher extends Person{
  public Teacher(){
      this.name = "老师";
  }
}

 

所有类型的class

package JavaStudy.Reflection;

import java.lang.annotation.ElementType;

//所有类型的Class
public class Test03 {
  public static void main(String[] args) {
      Class c1 = Object.class;//类
      Class c2 = Comparable.class;//接口
      Class c3 = String[].class;//一维数组
      Class c4 = int[][].class;//二维数组
      Class c5 = Override.class;//注解
      Class c6 = ElementType.class;//枚举类型
      Class c7 = Integer.class;//基本类型
      Class c8 = void.class;//void
      Class c9 = Class.class;// Class

      System.out.println(c1);
      System.out.println(c2);
      System.out.println(c3);
      System.out.println(c4);
      System.out.println(c5);
      System.out.println(c6);
      System.out.println(c7);
      System.out.println(c8);
      System.out.println(c9);
      int a[] = new int[10];
      int b[] = new int[5];

      //只要元素类型与维度一样 class一样
      System.out.println(a.getClass().hashCode());
      System.out.println(b.getClass().hashCode());
  }
}

 

分析类的加载器(还没有分析)

 

分析类初始化

image-20210408173114086

//测试类的初始化

import java.sql.SQLOutput;

public class test04 {
  static{
      System.out.println("main类被加宰");
  }

  public static void main(String[] args) throws ClassNotFoundException {
      //1.主动引用S
      //Son son = new Son();

      /*输出结果:
      main类被加宰         父类被加宰     子类被加载 */

      //2.反射引用
      //Class.forName("JavaStudy.Reflection.Son");

      /*输出结果:
      main类被加宰         父类被加宰     子类被加载 */

      //不会初始化的方法
      //1.子类调用父类的静态方法
      //System.out.println(Son.m);
      //输出 main类加载 父类被加宰 0

      //2。数组
      Son[] son = new Son[5];//输出main类被调用 其他没有

//3.子类的静态常量
      System.out.println(Son.M);//输出main类被调用 其他没有



  }
}

class Father{
  static{
      System.out.println("父类被加宰");

  }
  static int m =0;

}

class Son extends Father{
  static {
      System.out.println("子类被加载");
  }
}

 

 

类加载器(还未总结)

 

 

获取类的运行时结构

package JavaStudy.Reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLOutput;

//获得类的信息
public class test05 {
  public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
      Class c1 = Class.forName("JavaStudy.Reflection.User");

      //获得类的名字
      System.out.println(c1.getName()); //获得包名+类名
      System.out.println(c1.getSimpleName()); //获得类名

      //获得类的属性
      System.out.println("====================");
      Field[] fields = c1.getFields();//只能找到public类的属性

      fields = c1.getDeclaredFields();//找到全部属性
      for (Field field : fields) {
          System.out.println(field);
      }

      //获得指定属性的值
      Field name = c1.getDeclaredField("name");
      System.out.println(name);


      //获得类的方法
      System.out.println("================方法");
      Method[] methods = c1.getMethods();//获得public方法
      for (Method method : methods) {
          System.out.println(methods);
      }

      methods = c1.getDeclaredMethods();//获得全部方法
      for (Method method : methods) {
          System.out.println(methods);
      }

      //获得指定名字的方法
      //需要方法的参输 和类型.class
      Method getname = c1.getMethod("getName", null);
      Method setName = c1.getMethod("setName", String.class);
      System.out.println(getname);
      System.out.println(setName);

      //获得指定类的构造器
      Constructor[] constructor = c1.getConstructors();
      constructor = c1.getDeclaredConstructors();
      for (Constructor constructor1 : constructor) {
          System.out.println(constructor);
      }
      //获得指定的构造器
      Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
      System.out.println(declaredConstructor );
  }
}

 

动态创建对象执行方法

调用方法:

USer user =(User)c1.newInstance();

c1.invoke(user,"setName");

 

调用属性

USer user =(User)c1.newInstance();

Field name=c1.getDeclaredField("name")//属性的名

name.set(user,"luyang");//如果是private类 在前面加 name.setAccessible(true);

 

性能对比分析

package JavaStudy.Reflection;
//性能对比分析

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class test07 {


  //普通方式调用
  public static void test1(){
      User user = new User();

      long start = System.currentTimeMillis();

      for (int i = 0; i < 1000000000; i++) {
          user.getName();
      }

      long end = System.currentTimeMillis();
      System.out.println("普通方法执行10亿次数"+(end-start)+"ms");
  }

  //反射方法调用
  public static void test2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException ,IllegalAccessException{
      User user = new User();
      Class c1= user.getClass();
      Method getName = c1.getDeclaredMethod("getName", null);

      long start = System.currentTimeMillis();

      for (int i = 0; i <1000000000; i++) {
          getName.invoke(user, null);
      }

      long end = System.currentTimeMillis();
      System.out.println("反射方法执行10亿次数"+(end-start)+"ms");
  }


  ////反射方法调用 关闭检测
  public static void test3() throws ClassNotFoundException, NoSuchMethodException ,InvocationTargetException ,IllegalAccessException{
      User user = new User();
      Class c1= user.getClass();
      Method getName = c1.getDeclaredMethod("getName", null);
      getName.setAccessible(true);

      long start = System.currentTimeMillis();

      for (int i = 0; i < 1000000000; i++) {
          getName.invoke(user, null);
      }

      long end = System.currentTimeMillis();
      System.out.println("关闭检测方法执行10亿次数"+(end-start)+"ms");
  }

  public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException ,InvocationTargetException ,IllegalAccessException{
      test1();

      test2();
      test3();

  }


}

 

反射操作泛型(未总结)

 

 

image-20210411145337390

 

 

获取注解信息

getAnnotations

getAnnotation

package JavaStudy.Reflection;

import java.lang.annotation.*;
import java.lang.reflect.Field;


//通过反射获取注解
public class test09 {
  public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {

      //通过反射获得注解
      Class c1= Class.forName("JavaStudy.Reflection.Student2");
      Annotation[] annotations = c1.getAnnotations();
      for (Annotation annotation : annotations) {
          System.out.println(annotation);
      }

      //获得注解的value值

      luyang luyang = (luyang)c1.getAnnotation(luyang.class);
      String value = luyang.value();
      System.out.println(value);


      //获得类的指定注解
      Field name = c1.getDeclaredField("name");
      Fieldyang annotation = name.getAnnotation(Fieldyang.class);
      System.out.println(annotation);
  }
}

@luyang("db-student")
class Student2{
  @Fieldyang(columnName = "db-name",type = "String",length = 10)
  private String name;
  @Fieldyang(columnName = "db-id",type = "int",length = 10)
  private int id;
  @Fieldyang(columnName = "db-age",type = "int",length = 2)
  private int age;

  public Student2() {
  }

  public Student2(String name, int id, int age) {
      this.name = name;
      this.id = id;
      this.age = age;
  }

  public String getName() {
      return name;
  }

  public int getId() {
      return id;
  }

  public int getAge() {
      return age;
  }

  public void setName(String name) {
      this.name = name;
  }

  public void setId(int id) {
      this.id = id;
  }

  public void setAge(int age) {
      this.age = age;
  }

  @Override
  public String toString() {
      return "id:" + id
              +"age:"+age+
              "name:" +name;
  }
}

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)

@interface luyang{
  String value();
}



//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldyang{
  String columnName();//列名
  String type();
  int length();
}

JUC 并发编程

 

1.什么是JUC

 

java.util工具包、包、分类

业务:普通的线程代码 Thread

Runnable 没有返回值 效率相比Callable相对较低

 

 

2.传统的synchronized

 

package JavaStudy.JUC;
//传统的synchronized
public class demo01 {
   public static void main(String[] args) {
       tickets t  =new tickets();
       new Thread(()->{
           for(int i =0;i<50;i++)
          {
               t.sole();
          }
      },"A").start();
       new Thread(()->{
           for(int i =0;i<50;i++)
          {
               t.sole();
          }
      },"B").start();
       new Thread(()->{
           for(int i =0;i<50;i++)
          {
               t.sole();
          }
      },"C").start();
  }

}
class tickets{
   int ticket =30;

   public synchronized void sole(){
       if(ticket>0)

       System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket+"张票 还剩下"+(30-ticket--));
  }
}

3.Lock锁

image-20210513231316946

 

image-20210513231112692

 

 

公平锁: 先来后到

非公平锁: 可以插队(默认的)

 

package JavaStudy.JUC;

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

//传统的synchronized
public class demo02lock {
   public static void main(String[] args) {
       tickets02 t = new tickets02();
       new Thread(()->{ for(int i =0;i<50;i++) t.sole(); },"A").start();
       new Thread(()->{ for(int i =0;i<50;i++) t.sole(); },"B").start();
       new Thread(()->{ for(int i =0;i<50;i++) t.sole(); },"C").start();
  }


}

//lock三部曲
//1.new ReentrantLock();
// lock.lock();加锁
//finally lock.unlock();解锁
class tickets02 {
   int ticket = 30;
   Lock lock = new ReentrantLock();


   public void sole() {
       lock.lock();//加锁
       try {//放业务代码
           if (ticket > 0)

               System.out.println(Thread.currentThread().getName() + "抢到了第" + ticket + "张票 还剩下" + (30 - ticket--));

      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           lock.unlock();//解锁
      }

  }
}

lock和synchronized的区别

 

1.synchronized 是内置的关键字 lock是关键类

2.synchronized 无法判断获取锁的状态 lock可以判断是否获取了锁

3.synchronized 会自动释放锁子 lock如果不释放锁会 死锁

4.synchronized 线程一:(获得锁、阻塞) 线程二会一直等 但是lock不一定会等下去

5.synchronized 可重入锁 不可以中断 非公平锁 lock 可重入锁 可以判断锁,可以设置是否公平

6.synchronized 适合锁少量代码同步问题 lock 驶合锁大量的同步的代码

 

什么是锁

 

4.生产者消费者问题

面试常问: 1.单例模式 排序算法 生产者消费者问题 死锁

synchronized版

package JavaStudy.JUC;

public class demo03消费者问题 {
   public static void main(String[] args) {
       Date date = new Date();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    date.increament();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
               try {
                   date.decreament();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      }, "B").start();

  }
}

//资源类
//判断等待 业务 通知
class Date{
   private int number = 0;

   public synchronized void increament() throws InterruptedException {
       if(number !=0) {
           this.wait();
      }
       number++;
       System.out.println(Thread.currentThread().getName()+"----"+number);
       this.notifyAll();

  }

   public synchronized void decreament() throws InterruptedException {
       if(number==0)
      {
           this.wait();
      }
       number--;
       System.out.println(Thread.currentThread().getName()+"----"+number);
       this.notifyAll();//通知其他线程 我减一完了

  }

}

出现问题:ABCD四个线程时 出现虚假唤醒

image-20210515144235068

 

解决方法: if改为 while方法

JUC 版生产者消费者

image-20210515145013037

通过lock找到codition方法

image-20210515144915569

 

代码实现“

package JavaStudy.JUC;

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

public class demo04生产者Lock {
   public static void main(String[] args) {
       Date2 date = new Date2();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
               try {
                   date.increament();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      }, "A").start();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
               try {
                   date.decreament();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      }, "B").start();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
               try {
                   date.increament();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      }, "C").start();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
               try {
                   date.decreament();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      }, "D").start();

  }


  }


//资源类
//判断等待 业务 通知
class Date2{
   private int number = 0;
   Lock lock = new ReentrantLock();
   Condition condition = lock.newCondition();

   public synchronized void increament() throws InterruptedException {

       lock.lock();
       try {
           while(number !=0) {
               condition.await();//等待
          }
           number++;
           System.out.println(Thread.currentThread().getName()+"----"+number);
           condition.signalAll();//唤醒
      }catch(Exception e){
           e.printStackTrace();
      }finally{
           lock.unlock();
      }


  }

   public void decreament() throws InterruptedException {
       lock.lock();
       try {
           while(number ==0) {
               condition.await();//等待
          }
           number--;
           System.out.println(Thread.currentThread().getName()+"----"+number);
           condition.signalAll();//唤醒
      }catch(Exception e){
           e.printStackTrace();
      }finally{
           lock.unlock();
      }


  }

}

 

condition 精准的通知和唤醒线程

image-20210515150344390

 

代码测试

package JavaStudy.JUC;

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

public class demo04condition顺序执行 {
   public static void main(String[] args) {
      Data4 date = new Data4();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
                 date.printA();
          }
      }, "A").start();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
               date.printB();
          }
      }, "B").start();

       new Thread(()->{
           for (int i = 0; i < 10; i++) {
           date.printC();
          }
      }, "C").start();



  }
}

class Data4{
   private Lock lock = new ReentrantLock();
   private Condition condition1 = lock.newCondition();
   private Condition condition2 = lock.newCondition();
   private Condition condition3 = lock.newCondition();

   private int flag = 1;

   public void printA(){
       lock.lock();
       try {
           while(flag!=1)
          {
               condition1.await();
          }
           System.out.println(Thread.currentThread().getName() + "----AAAAAAA");
           flag = 2;
           condition2.signal();//唤醒指定的condition2

      } catch (Exception e) {
           e.printStackTrace();
      }finally {
           lock.unlock();
      }

  }
   public void printB(){
       lock.lock();
       try {
           while(flag!=2)
          {
               condition2.await();
          }
           System.out.println(Thread.currentThread().getName() + "-----BBBBB");
           flag = 3;
           condition3.signal();//唤醒指定的condition2

      } catch (Exception e) {
           e.printStackTrace();
      }finally {
           lock.unlock();
      }

  }
   public void printC(){
       lock.lock();
       try {
           while(flag!=3)
          {
               condition3.await();
          }
           System.out.println(Thread.currentThread().getName() + "---CCCCC");
           flag = 1;
           condition1.signal();//唤醒指定的condition2

      } catch (Exception e) {
           e.printStackTrace();
      }finally {
           lock.unlock();
      }

  }
}

5. 8锁现象(跳了)

什么是锁 锁的是谁

 

6.集合类不安全

1.list不安全

并发修改异常

解决方案:1.用vector<>解决 (因为vector在源码中有synchroniezd的线性同步)

2.用List <String> list= Collections.synchronizedList(new ArrayList<>());

3.List <String> list= new CopyOnWriteArrayList<>(); x写入时复制

image-20210515160457040

 

2.set不安全

解决方案1:Set <String >set = Collections.synchronizedSet(new HashSet<>());

2.Set <String >set = new CopyOnWriteArraySet<>();

 

3.hashmap 不安全

1.collections.chronizedmap<>();

2.Map <String,String>map = new ConcurrentHashMap<>();

 

 

7.callable(跳)

 

8.常用的辅助类

 

 

9.读写锁

ReadWriterLock

image-20210517151908533

package JavaStudy.JUC;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/*
读写锁

读可以多线程读 读取的时候没完成 别的线程也可以读取
写必须要单线程写

ReadWriteLock 读写锁 读锁可以多线程插队 写锁必须每个线程排队
*/
public class demo06WriterReadLock {
   public static void main(String[] args) {
           MyCacheLock myCache =new MyCacheLock();

           //只做写入的操作
       for (int i = 1; i <= 5; i++) {
           final  int  temp = i;
           new Thread(()->{myCache.put(temp+"",temp+"");
          },String.valueOf(i)).start();
      }

       //只做读取的操作
       for (int i = 1; i <= 5; i++) {
           final  int  temp = i;
           new Thread(()->{myCache.get(temp+"");
          },String.valueOf(i)).start();
      }
  }
}
//加读写锁版本
class MyCacheLock{

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

   //存,读

   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()+ "写入完成 ");
      } 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()+ "读取成功 ");
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           readWriteLock.readLock().unlock();
      }
      }
  }



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()+ "写入完成 ");
  }

   //取,写
   public  void get(String key){
       System.out.println(Thread.currentThread().getName()+ "读取 "+key);
       Object o =map.get(key);
       System.out.println(Thread.currentThread().getName()+ "读取成功 ");
  }

}

 

10.阻塞队列BlockingQueue

阻塞

队列

image-20210517155019998

 

阻塞队列:

image-20210517154955334

BlockingQuene 不是新概念 就是集合中quene的一种

 

什么情况下会用:多线程并发操作 线程池

 

image-20210517155834577

 

学会使用队列

添加、移除

四组API

四组API抛出异常有返回值阻塞等待超时等待
添加 add offer put offer(,,)
移除 remove poll take poll(,,)
判断队首 element peek    

1.抛出异常

public static  void test(){
   ArrayBlockingQueue 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()); 队列已经空了 抛出异常


}

2.不会抛出异常

//有返回值
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("d"));


   System.out.println(blockingQueue.poll());//返回移除的值
   System.out.println(blockingQueue.poll());
   System.out.println(blockingQueue.poll());
   System.out.println(blockingQueue.poll());//返回null


}

3.阻塞等待

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());



}

4.超时等待

public  static  void test4() throws InterruptedException {
   ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

   System.out.println(blockingQueue.offer("a"));
   System.out.println(blockingQueue.offer("b"));
   System.out.println(blockingQueue.offer("c"));

   blockingQueue.offer("d",2, TimeUnit.SECONDS);//超过两秒结束等待
   //blockingQueue.put("d");

   System.out.println(blockingQueue.poll());
   System.out.println(blockingQueue.poll());
   System.out.println(blockingQueue.poll());
   System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));




}

同步队列 SynchronizedQueue

package JavaStudy.JUC.testBlockingQuene;

import java.util.Timer;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/*
*同步队列
* 和其他的blockingQueue不同 SynchronousQueue 不储存元素
* 从里面put一个元素后 必须从里面先take一个元素 否则不能put值
*
*/

public class SynchronousQuene {
   public static void main(String[] args) {
       BlockingQueue<String> blockingQueue = new SynchronousQueue<>();//同步队列

       new Thread(()->
      {
           try {
               System.out.println(Thread.currentThread().getName() + "--->put1 ");
               blockingQueue.put("1");
               System.out.println(Thread.currentThread().getName() + "--->put2 ");
               blockingQueue.put("2");
               System.out.println(Thread.currentThread().getName() + "--->put3 ");
               blockingQueue.put("3");
          }catch(InterruptedException e){
               e.printStackTrace();

          } },"T1").start();
       new Thread(()->
      {

           try {
               TimeUnit.SECONDS.sleep(2);
               System.out.println(Thread.currentThread().getName() + "-->"+blockingQueue.take());
               TimeUnit.SECONDS.sleep(2);
               System.out.println(Thread.currentThread().getName() + "-->"+blockingQueue.take());
               TimeUnit.SECONDS.sleep(2);
               System.out.println(Thread.currentThread().getName() + "-->"+blockingQueue.take());

          }catch(InterruptedException e){
               e.printStackTrace();

          } },"T2").start();


  }
}

10.线程池(重点)

池化技术

image-20210517181944895

线程池三大方法

package JavaStudy.JUC.ThreadPool;

import sun.nio.ch.ThreadPool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
*@Author:ly
*Date: 15:38
线程池三大方法
*@return
*/
public class 三大方法 {
   public static void main(String[] args) {
       //ExecutorService threadPool =Executors.newSingleThreadExecutor();//单个线程
       ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建一个的线程池大小
//Executors.newCachedThreadPool();//可伸缩的欲将则强 遇弱则弱

       try {
           for (int i = 0; i < 10; i++) {
               threadPool.execute(()->{//使用线程池后 用线程池来创建线程
                   System.out.println(Thread.currentThread().getName()+" ook");
              });

          }
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           threadPool.shutdown();//线程池用完 程序结束 关闭线程池
      }
  }
}

 

七大参数

public static ExecutorService newSingleThreadExecutor() {
   return new FinalizableDelegatedExecutorService
      (new ThreadPoolExecutor(1, 1,
                               0L, TimeUnit.MILLISECONDS,
                               new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
   return new ThreadPoolExecutor(nThreads, nThreads,
                                 0L, TimeUnit.MILLISECONDS,
                                 new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
   return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                 60L, TimeUnit.SECONDS,
                                 new SynchronousQueue<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.acc = System.getSecurityManager() == null ?
               null :
               AccessController.getContext();
       this.corePoolSize = corePoolSize;
       this.maximumPoolSize = maximumPoolSize;
       this.workQueue = workQueue;
       this.keepAliveTime = unit.toNanos(keepAliveTime);
       this.threadFactory = threadFactory;
       this.handler = handler;
  }

 

 

七大参数

image-20210519155501220

 

 

package JavaStudy.JUC.ThreadPool;

import java.util.concurrent.*;
//四种拒绝策略
//1.ThreadPoolExecutor.AbortPolicy()//银行满了 但是还有人进来 就不处理 抛出异常
//2. new ThreadPoolExecutor.DiscardPolicy()//队列满了不会抛出异常 丢掉任务
//3.new ThreadPoolExecutor.CallerRunsPolicy()//哪里来的回到哪去
//4.new ThreadPoolExecutor.DiscardOldestPolicy()//队列完了就尝试和第一个竞争 不会抛出异常

public class 线程池七大参数 {
   public static void main(String[] args) {

       ExecutorService threadPool = new ThreadPoolExecutor(
               2,//核心线程大小
               5,//最大线程
               3,//超时等待
               TimeUnit.SECONDS,//时间单维
               new LinkedBlockingQueue<>(3),
               Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.DiscardOldestPolicy()
               //new ThreadPoolExecutor.CallerRunsPolicy()
              // new ThreadPoolExecutor.AbortPolicy()//银行满了 但是还有人进来 就不处理 抛出异常
      );

       try {
           for (int i = 0; i < 10; i++) {
               threadPool.execute(()->{//使用线程池后 用线程池来创建线程
                   System.out.println(Thread.currentThread().getName()+" ook");
              });

          }
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           threadPool.shutdown();//线程池用完 程序结束 关闭线程池
      }
  }
}

 

 

 

 

 

四种拒绝策略

image-20210519160144439

//四种拒绝策略
//1.ThreadPoolExecutor.AbortPolicy()//银行满了 但是还有人进来 就不处理 抛出异常
//2. new ThreadPoolExecutor.DiscardPolicy()//队列满了不会抛出异常 丢掉任务
//3.new ThreadPoolExecutor.CallerRunsPolicy()//哪里来的回到哪去
//4.new ThreadPoolExecutor.DiscardOldestPolicy()//队列完了就尝试和第一个竞争 不会抛出异常

 

 

11.ForkJoinOn(未总结)

12.异步回调(未总结)

 

13.理解JMM

image-20210520091135444

 

存在问题:线程B修改了值 但是线程A 不能及时可见

八种操作:

image-20210520091431181

 

image-20210520092157855

需要让线程A知道主内存的值发生变化了

14.Volatile

三个特性:

1.可见性

2.不保证原子性

3.禁止指令重排

 

特性1 :保证可见性

给变量修饰的时候加volatile就可以保证线程A同步

 

特性2:不保证原子性

原子性:不可分割

线程A在执行任务的时候 不能被打扰 也不能被分割 要么同时成功 要么同时失败

package JavaStudy.JUC.JMM;

import java.util.concurrent.atomic.AtomicInteger;

//volitile不保证原子性
//如何保证原子性? 使用原子类
public class Volatile不保证原子性 {
    private static AtomicInteger num =new AtomicInteger();
   public static  void run(){
       num.getAndIncrement();//++操作
  }
   public static void main(String[] args) {
       for (int i = 0; i < 20; i++) {
           new Thread(()->{
               for (int j = 0; j < 1000; j++) {
                       run();
              }
          }).start();
      }

       while (Thread.activeCount()>2)
      {
           Thread.yield();
      }
       System.out.println(num);
  }
}

 

15.指令重排详解

指令重排

你写的程序 计算机并不是按照你写的呢样执行

源代码 ->编译器优化的重排 -->指令并行也会重排 --->内存系统一会重排---》执行

image-20210520095431611

image-20210520095443977

16.单例模式

深究!

饿汉式

package JavaStudy.JUC.单例模式;

//饿汉式
//缺点 可能浪费空间
public class Hungry {
   //浪费空间 一上来就全部创建

   private final  static int[] a =new int[1024*1024];
   private final  static int[] a1 =new int[1024*1024];
   private final  static int[] a2 =new int[1024*1024];
   private final  static int[] a3 =new int[1024*1024];
   private Hungry(){

  }
   private final  static Hungry hungry = new Hungry();

   public  static Hungry getInstance(){
       return hungry;
  }
}

DCL 懒汉式

package JavaStudy.JUC.单例模式;

//懒汉式
public class lazyMan {
   private lazyMan(){
       System.out.println(Thread.currentThread().getName() + "ok");

  }
   private  volatile static  lazyMan lazyman;
   //懒汉式的双重检测锁模式单例 DCL懒汉式
   public static lazyMan getInstance(){
       if(lazyman==null) {
           synchronized (lazyMan.class){
               if(lazyman==null)
               lazyman =new lazyMan();//不是原子性操纵
               /*1.分配内存空间
                * 2.执行构造方法 初始化对象
                * 3.把这个对像指向这个空间
                *
                * 可能存在指令重排
                */
          }

      }
       return lazyman;
  }

   //多线程并发
   public static void main(String[] args) {
       for (int i = 0; i < 10; i++) {
           new Thread(()->{
               getInstance();
          }).start();
           
      }
  }

}

 

静态内部类

 

package JavaStudy.JUC.单例模式;
//静态内部类
public class Holder {
   //单例模式 构造器私有
   private Holder(){

  }
   public static  Holder getInstance(){
       return InnerClass.holder;
  }
   public static  class InnerClass{
       private static final Holder holder = new Holder();

  }
}

 

用反射破解的话 单例不安全 所以要用枚举

   //enum 是什么? enum本身就是一个Class 类
public enum EnumSingle {
   INSTANCE;
   public EnumSingle getInstance(){
       return INSTANCE;
  }
}

class Test{
   public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       EnumSingle instance1 = EnumSingle.INSTANCE;
       Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
       declaredConstructor.setAccessible(true);
       //java.lang.NoSuchMethodException: com.ogj.single.EnumSingle.<init>()
  EnumSingle instance2 = declaredConstructor.newInstance();
   System.out.println(instance1);
   System.out.println(instance2);
}
}

17.深入理解CAS

什么是CAS(期望和更新)

public class casDemo {
   //CAS : compareAndSet 比较并交换
   public static void main(String[] args) {
       AtomicInteger atomicInteger = new AtomicInteger(2020);

       //boolean compareAndSet(int expect, int update)
       //期望值、更新值
       //如果实际值 和 我的期望值相同,那么就更新
       //如果实际值 和 我的期望值不同,那么就不更新
       System.out.println(atomicInteger.compareAndSet(2020, 2021));
       System.out.println(atomicInteger.get());

       //因为期望值是2020 实际值却变成了2021 所以会修改失败
       //CAS 是CPU的并发原语
       atomicInteger.getAndIncrement(); //++操作
       System.out.println(atomicInteger.compareAndSet(2020, 2021));
       System.out.println(atomicInteger.get());
  }
}

在这里插入图片描述

Unsafe类

在这里插入图片描述

 

在这里插入图片描述

总结:

CAS:比较当前工作内存中的值 和 主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环,使用的是自旋锁。

缺点:

  • 循环会耗时;

  • 一次性只能保证一个共享变量的原子性;

  • 它会存在ABA问题

 

CAS:ABA问题?(狸猫换太子)

 

在这里插入图片描述

 

线程1:期望值是1,要变成2;

线程2:两个操作:

  • 1、期望值是1,变成3

  • 2、期望是3,变成1

所以对于线程1来说,A的值还是1,所以就出现了问题,骗过了线程1;

 

 

public class casDemo {
   //CAS : compareAndSet 比较并交换
   public static void main(String[] args) {
       AtomicInteger atomicInteger = new AtomicInteger(2020);

       System.out.println(atomicInteger.compareAndSet(2020, 2021));
       System.out.println(atomicInteger.get());

       //boolean compareAndSet(int expect, int update)
       //期望值、更新值
       //如果实际值 和 我的期望值相同,那么就更新
       //如果实际值 和 我的期望值不同,那么就不更新
       System.out.println(atomicInteger.compareAndSet(2021, 2020));
       System.out.println(atomicInteger.get());

       //因为期望值是2020 实际值却变成了2021 所以会修改失败
       //CAS 是CPU的并发原语
//       atomicInteger.getAndIncrement(); //++操作
       System.out.println(atomicInteger.compareAndSet(2020, 2021));
       System.out.println(atomicInteger.get());
  }
}

 

18.原子引用

解决ABA问题,对应的思想:就是使用了乐观锁~

带版本号的 原子操作!

Integer 使用了对象缓存机制,默认范围是-128~127,推荐使用静态工厂方法valueOf获取对象实例,而不是new,因为valueOf使用缓存,而new一定会创建新的对象分配新的内存空间。

在这里插入图片描述

 

所以如果遇到,使用大于128的时候,使用原子引用的时候,如果超过了这个值,那么就不会进行版本上升!

在这里插入图片描述

那么如果我们使用小于128的时候:

在这里插入图片描述

package JavaStudy.JUC.CAs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

public class demo02 {
   public static void main(String[] args) {
       //注意 如果泛型是一个包装类 注意对象的引用问题
       //正常在业务操作中 这里面的比较都是---对象
       AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);

       new Thread(()->{

           int stamp = atomicStampedReference.getStamp();//获得版本号
           System.out.println("a1---"+atomicStampedReference.getStamp());
           try {
               TimeUnit.SECONDS.sleep(2);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
           atomicStampedReference.compareAndSet(1,2,
                   atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);

           System.out.println("a2---"+atomicStampedReference.getStamp());
           atomicStampedReference.compareAndSet(2,1,
                   atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);

           System.out.println("a3---"+atomicStampedReference.getStamp());

      },"a").start();
       new Thread(()->{

           int stamp = atomicStampedReference.getStamp();//获得版本号
           System.out.println("b1---"+atomicStampedReference.getStamp());
           try {
               TimeUnit.SECONDS.sleep(2);
          } catch (InterruptedException e) {
               e.printStackTrace();}
           atomicStampedReference.compareAndSet(1,3,stamp,stamp+1);

           System.out.println("b1----"+atomicStampedReference.getStamp());

      },"b").start();


  }
}

正常业务操作中,我们一般使用的是一个个对象,一般情况不会遇到这种情况。

19.各种锁的理解

1.公平锁 非公平锁

公平锁:非常公平;不能插队的,必须先来后到;


  public ReentrantLock() {
  sync = new NonfairSync();
  }
  • 非公平锁:非常不公平,允许插队的,可以改变顺序。

Lock lock = new ReentrantLock();//默认是非公平锁 Lock lock2 = new ReentrantLock(true); //设置为公平锁

public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
 


#### 2.可重入锁

可重入锁(递归锁)

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200727214440726.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxNjE3ODQ4,size_16,color_FFFFFF,t_70)

> Synchronized锁

```java
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锁

/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 void sms(){
       lock.lock(); //细节:这个是两把锁,两个钥匙
       //lock锁必须配对,否则就会死锁在里面
       try {
           System.out.println(Thread.currentThread().getName()+"=> sms");
           call();//这里也有一把锁
      } catch (Exception e) {
           e.printStackTrace();
      }finally {
           lock.unlock();
      }
  }
   public void call(){
       lock.lock();
       try {
           System.out.println(Thread.currentThread().getName() + "=> call");
      }catch (Exception e){
           e.printStackTrace();
      }
       finally {
           lock.unlock();
      }
  }

 

3.自旋锁

spinlock

public final int getAndAddInt(Object var1, long var2, int var4) {
   int var5;
   do {
       var5 = this.getIntVolatile(var1, var2);
  } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
   return var5;
}

自我设计自旋锁:

public class SpinlockDemo {

   //int 0
   //thread null
   AtomicReference<Thread> atomicReference=new AtomicReference<>();

   //加锁
   public void myLock(){
       Thread thread = Thread.currentThread();
       System.out.println(thread.getName()+"===> mylock");

       //自旋锁
       while (!atomicReference.compareAndSet(null,thread)){
           System.out.println(Thread.currentThread().getName()+" ==> 自旋中~");
      }
  }


   //解锁
   public void myunlock(){
       Thread thread=Thread.currentThread();
       System.out.println(thread.getName()+"===> myUnlock");
       atomicReference.compareAndSet(thread,null);
  }

}

测试

public class TestSpinLock {
   public static void main(String[] args) throws InterruptedException {
       ReentrantLock reentrantLock = new ReentrantLock();
       reentrantLock.lock();
       reentrantLock.unlock();


       //使用CAS实现自旋锁
       SpinlockDemo spinlockDemo=new SpinlockDemo();
       new Thread(()->{
           spinlockDemo.myLock();
           try {
               TimeUnit.SECONDS.sleep(3);
          } catch (Exception e) {
               e.printStackTrace();
          } finally {
               spinlockDemo.myunlock();
          }
      },"t1").start();

       TimeUnit.SECONDS.sleep(1);


       new Thread(()->{
           spinlockDemo.myLock();
           try {
               TimeUnit.SECONDS.sleep(3);
          } catch (Exception e) {
               e.printStackTrace();
          } finally {
               spinlockDemo.myunlock();
          }
      },"t2").start();
  }
}

运行结果:

t2进程必须等待t1进程Unlock后,才能Unlock,在这之前进行自旋等待。。。。

 

4.死锁

死锁是什么?

在这里插入图片描述

死锁测试,怎么排除死锁:

package com.ogj.lock;

import java.util.concurrent.TimeUnit;

public class DeadLock {
   public static void main(String[] args) {
       String lockA= "lockA";
       String lockB= "lockB";

       new Thread(new MyThread(lockA,lockB),"t1").start();
       new Thread(new MyThread(lockB,lockA),"t2").start();
  }
}

class MyThread implements Runnable{

   private String lockA;
   private String lockB;

   public MyThread(String lockA, String lockB) {
       this.lockA = lockA;
       this.lockB = lockB;
  }

   @Override
   public void run() {
       synchronized (lockA){
           System.out.println(Thread.currentThread().getName()+" lock"+lockA+"===>get"+lockB);
           try {
               TimeUnit.SECONDS.sleep(2);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
           synchronized (lockB){
               System.out.println(Thread.currentThread().getName()+" lock"+lockB+"===>get"+lockA);
          }
      }
  }
}

解决问题

1、使用jps定位进程号,jdk的bin目录下: 有一个jps

命令:jps -l

image-20210520232104735

 

2、使用jstack 进程号 找到死锁信息

一般情况信息在最后:

 

 

面试,工作中!排查问题!

1、日志

2、堆栈信息

 

20.JUC小结及资料说明

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

JVM探究

image-20210427234913972

 

什么是jvm

 

1.jvm的位置

image-20210502195204021

 

 

2.jvm体系结构

 

image-20210502195749681

 

 

image-20210502195848425

 

3.类加载器和双亲委派机制

image-20210505215048428

1.虚拟机自带的加载器

2.启动类(根)加载器、

3.扩展类加载器

4.应用程序加载器

双亲委派机制

//双亲委派机制:安全
   //1.APP(当前应用加载器)--->EXC--->BOOT(最终执行)
   //BOOT 根加载器 或者启动类加载器
   //EXC 扩展类加载器
   //APP 应用程序加载器


   /*
   1.类的加载器收到类加载的请求
   2.将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器
   3.启动类加载器检查是否能够加宰当前这个类 能加在就结束 使用当前的加载器 否则抛出异常 通知子类加载器进行加宰
   4.重复步骤三
    */
}

 

参考连接:https://blog.csdn.net/codeyanbao/article/details/82875064?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162021897716780262514102%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162021897716780262514102&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-82875064.nonecase&utm_term=%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE%E6%9C%BA%E5%88%B6&spm=1018.2226.3001.4187

JVM中提供了三层的ClassLoader:

  • Bootstrap classLoader:主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和APPClassLoader。

  • ExtClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。

  • AppClassLoader:主要负责加载应用程序的主函数类

image-20210505231539655

为什么要设计这种机制 这种设计有个好处是,如果有人想替换系统级别的类:String.java。篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了(为什么?因为当一个类需要加载的时候,最先去尝试加载的就是BootstrapClassLoader),所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。

总结了一张脑图如下:

 

 

4.沙箱安全机制

 

5.native和方法区

native

//native: 凡是带了native关键字的 说明java的作用范围到达不了了 回去调用底层c语言的库!
   //会进入本地方法栈
   //调用本地方法接口(JNI)
   //JNI 的作用: 扩展java的使用 融合不同的编程语言为java所用! 最初:c++、c
   //他在内存区域中专门开辟了一块标记区域:native Method stack 本地方法栈 登记native方法
   //在最终执行的时候 加宰 本方法中的方法通过JNI
   public native void run();
}

 

image-20210506201328835

 

image-20210506223325279

方法区存放 类.class 和常量池

栈 :存放应用地址 指向堆中类的实例化对象

堆:存放类的实例化对象

参考链接:https://blog.csdn.net/qq_39581763/article/details/97369651?ops_request_misc=&request_id=&biz_id=102&utm_term=java%20jvm%E4%B8%AD%E7%9A%84native&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-97369651.pc_search_result_hbase_insert&spm=1018.2226.3001.4187

 

6.深入了解栈

栈:栈内存 主管程序的运行,生命周期和线程同步

线程结束 栈内存就释放了,对于栈来说不存在垃圾回收问题

线程结束 栈就over

栈中存放的东西: 8大基本类型+对象引用+实例的方法

 

栈运行的原理: 栈帧

 

image-20210506221751294

 

image-20210506222934985

7.hotspot和堆

三种jvm

  • sun公司 HotSpot

  • BEA公司

  • IBM j9vm

     

Heap(堆) 一个jvm只有一个堆内存 堆内存的大小是可以调节的

类加载器读取了类文件后 一般会把什么东西放到堆中? 类,方法,变量,常量~,保存我们所有的引用类型的真实对象;

堆内存中还要细分为三个区域:

  • 新生区 (伊甸园区)Young/New

  • 养老区 Old

  • 永久区 Perm

 

image-20210509115800783

 

GC 垃圾回收。主要是在伊甸园区和养老区~

假设内存满了 报错OOM,堆内存不够!

java.lang.OUtOfMemoyError:java Heap Space

在JDK8以后 永久存储区改了名字(元空间)

 

8.新生区 养老区 永久区内存调优

新生区

  • 类:诞生的地方 甚至死亡

  • 伊甸园: 所有的对象都是在 伊甸园区new 出来的 满了就 轻GC

  • 幸存0 1 区: 重GC

     

永久区

这个区域常驻内存的,用来存放JDK自身携带的class对象,interface元数据,存储的是java运行时的一些环境或类信息 这个区域不存在垃圾回收 关闭jvm虚拟机就会释放这个区域的内存

一个启动类加载了大量的jar包 Tomcat部署了太多的应用 大量动态生成的反射类。 不断被加宰 知道内存满 就会出现OOM

  • jdk1.6 之前在 永久代 常量池在方法区

  • jdk1.7 永久代 慢慢退化 常量池在堆

  • jdk1.8 去除永久代 常量池在元空间

 

image-20210509212817443

 

方法区中有常量池

 

逻辑上存在 物理上不存在

 

package JavaStudy.jvm;

public class demo03runtimesize {
   public static void main(String[] args) {
       long max_runtime = Runtime.getRuntime().maxMemory();
       long total_runtime = Runtime.getRuntime().totalMemory();
       System.out.println("最大运行内存:"+max_runtime/(double)1024/1024+"MB");

       System.out.println("初始化运行内存:"+total_runtime/(double)1024/1024+"MB");

       //默认的情况下 分配的总内存是电脑内存的1/4       初始化 是1/64

       //OOM:
           //1.调节堆内存大小 扩大堆内存
           //2.分许内存 看一下那个地方出现了问题
       //-Xms1024m -Xmx1024m -XX:+PrintGCDetails 手动调节堆内存大小
  }
}

 

GC 介绍与引用计数法

GC : 垃圾回收

image-20210509215429420

 

GC的作用区域只有堆和方法区

jvm进行GC时 并不是对这三大区域统一回收 大部分的时候 都是回收新生代

  • 新生代

  • 幸存区(from to)

  • 老年区

     

GC的分类: 轻GC(普通的GC) 重GC(全局的GC)

 

image-20210510165845152

算法: 标记清除法 标记压缩法 复制算法 引用计数器法

 

引用计数器法:

image-20210510165952557

对象计数器为0 时被回收

 

复制算法

 

image-20210510171450683

 

默认15次GC后存入老年代

自我理解

当轻GC后 Eden区幸存下来的对象将会进入到的幸存区to 区中 from中的对象复制后放入到to对象中(to对象一般是空的) 然后清空from区的对象 同时 from区变为to 区 to 区变为from区(谁空谁是to区)

image-20210510172534591

复制算法的好坏处:

  • 好处:没有内存的碎片~

  • 坏处:浪费了内存空间 多了一半空间永远是空的

想要复制算法最佳使用场景: 对象存活度较低的时候 : 新生区

 

标记清除算法与标记压缩算法

 

标记清除算法:

image-20210510173712926

 

对活着的对象进行标记 清除没有标记的对象

  • 优点:不需要额外的空间

  • 缺点:两次扫描严重浪费时间 会产生内存碎片

 

标记压缩:

对标记清除再优化

image-20210510174100827

 

 

标记清除压缩

先标记清除几次 在进行一次压缩

 

总结

内存效率:复制> 标记清除 >标记压缩 (时间复杂度)

内存整齐度:复制 =标记压缩 > 标记清除

内存利用率:标记压缩 = 标记清除 > 复制算法

 

思考:难道没有最优的算法吗?

没有最好的算法 只有最合适的算法 ------->GC :分代收集算法

 

年轻代:

  • 存活率低 所以用复制算法

     

老年代:

  • 存活率高 区域大

  • 适合 标记清除(内存碎片不是太多)+标记压缩 混合实现

  •  

 

 

 

 

posted @ 2021-05-21 09:14  帅阳阳1  阅读(48)  评论(0)    收藏  举报