Map集合 File类 递归 序列化 常用类 进程线程 死锁

一.Map集合

将键映射到值得对象,键得值不能重复,一个键可以对应最少一个值。

Map接口下的封装好得实现类

–|HashMap

–|TreeMap

1.Map接口下的方法

增:
    //将指定得值与该映射中得指定键相关联
    V    put(k key,v value)
    //将指定地图的所有映射复制到此映射
    v    putAll(Map<? extends k,? extends v> m)
    
删:
    //通过键删除指定的值  返回值是被删除的值
    v    remove(k key):	
	//当键没有的话,就是添加,没有的话,就是覆盖
	V    put(K key, V value):	
	int       size(); // 查看集合中的元素的个数
	boolean   isEmpty(); //判断集合是否为空
	//判断集合中是否包含这个键
	boolean    containsKey(Obejct Key);  
	//判断集合中是否包含这个值
	boolean    containsValue(Obejct value);  

重要方法:
    v             get(k key)//通过键获取值
    //Set<String> strings = map.keySet();
    set<k>        keyset()//获取所有的键存到set集合中
    //Collection<String> values = map.values();
    Collection<V>	values()   获取所有集合中的值
    //Set<Map.Entry<k,v>>  set = map.entrySet();
    Set<Map.Entry<K,V>> entrySet()  //将键值对 的map的实体存到set集合中

2.Map集合的value值可以放对象

格式:
class Person{

}
main{
	Map<Integer,Person> map = new HashMap<>();
    map.put(1,new Perspn("he",18));
    sout(map.get(1).getName())//he
}

3.Map集合可以用LIst一键对多值

  Map<Integer, List<String>> map = new HashMap<>();
        List<String> list = new ArrayList<>();
        list.add("旺财");
        list.add("狗蛋");
        list.add("常威");

        map.put(1,list);
        List<String> list1 = new ArrayList<>();
        list1.add("来福");
        list1.add("坤坤");
        list1.add("存爱");
        map.put(2, list1);
        System.out.println(map);
    }

二.File类

相对路径:

​ 得有一个参照物

​ ./代表的是当前的工作目录

​ …/上一级目录

​ …/…/上两级目录

​ …/…/…/上三级目录

绝对路径:

​ 从磁盘的跟目录一直到文件的所在位置

​ D:/aaa/1.txt

1.File的构造方法

格式1File file = new File("D:/aaa/1.txt");
格式2File file = new File("c:/aaa", "1.txt");
格式3:
	File file = new File("C:\\aaa\\1.txt")

2.File下的方法

增:
boolean		createNewFile();//新建一个文件
boolean		mkdir();//创建单级目录
boolean		mkdirs();//创建多级目录
删:
boolean		delete();//删除文件或文件夹
查:返回值boolean
boolean		isFile()://是否是文件
boolean		isDirectory();//是否是文件夹
boolean		isHidden();//是否是隐藏文件
boolean		isAbsolute();//是否是绝对路经
boolean  	exist();//文件或文件夹是否存在
查:返回值String
String		getName();//获取文件或着文件夹的名字
String		getParent();//获取上一级目录
String		getPath();//获取File对象的绝对路径:返回值long
long		length();//获取文件占用磁盘的字节数
long		lastModified();//获取文件修改时间 时间戳:获取当前文件夹下面的所有的文件
File[]		listFiles();
	File[] files = file.listFiles();
String		list();
	String[] list = file.list();

三.递归

一个方法多次调用自己 , 但是得有结束得条件在递归第哦啊用的过程中 , 系统为每一层的返回点或者局部变量开辟了栈来存储 .

//求1-100的和,使用递归的方式来写
public static void main(String[] args) {
        System.out.println(sum(1));
    }
public static int sum(int num){
    if(num == 101){
        return 0;
    }
    return num + sum(num + 1);
}
//删除某一个目录下面的所有文件
public static void main(String[] args) {
    File file = new File();
    del(file);
}
	public static void del(File file){
         //找到bbb文件夹下面所有的文件和文件夹
        File[] files = file.listFiles();
        for(File file1 : filse){
            if(file1.isDirectory()){
                del(file1);
            }else{
                file1.delete();
            }
        }
    }

四.io流

1.io流概念

以后会遇到 上传和下载 等这些需求。

I input 输入

O output 输出

咱们电脑上面文件,在进行读取和存储的时候,都是以流的形式进行操作的

流这个概念是比较抽象的

2.缓冲的概念

看视频有点卡? 暂停的时候在缓冲的

缓冲其实就是为了提高读取和存储的效率的

计算机通过cpu读取硬盘的数据,在Java中可以加上缓冲的概念,每次读取具体的缓冲值。可以提高效率

3.IO流

从磁盘(c盘)读取数据到内存(Java代码) 1.txt====》java代码(输出出来)

输入流:

​ input :场景使用 从磁盘的c:/aaa/1.txt文件中 读取数据 到内存中(Java代码)

​ 字节输入流

​ 字符输入流

从内存(Java代码 String=“狗蛋”)写入数据到 磁盘(c盘 1.txt)

输出流:

​ output : 从内存(String str = " 还是数据库的") 写入到磁盘的c:/aaa/1.txt文件中

​ 字节输出流:

​ 字符输出流

参照物体 是内存

3.1字节输入流

FileInputStream

作用:将磁盘上面文件的内容读取到java代码中

public static void mian(String[] args) throwe IOException {
    //1.创建一个file对象的  文件抽象
    File file = new File(D:/aaa/1.txt);
     //2.创建字节输入流的核心的类
    FileInputStream fis = new FileInputStream(file);
     //3.加缓冲功能
    BufferedInputStream bis = new BUfferedInputStream(fis);
     //4.创建一个数组  缓冲数组
    baby[] buf = new baby[1024];
    int length;
    while((length = bis.read(buf)) != -1){
        System.out.println(new String(buf,0,length));
    }
    bis.close();
    fis.close();
}

简写:
BufferedInpubStream bis = new BufferedInpubStream(new  FileInputStream(new File(D:/aaa/1.txt)))

3.2字节输出流

FileOutpubStream

将Java代码中的一个字符串 写入到磁盘中的一个1.txt

public static void mian(String[] args) throwe IOException {
   //1.创建文件对象
   File file = new File("c:/aaa/2.txt");
   //2.创建核心的字节输出流对象FileOutputStream
   FileOutputStream fos = new FileOutputStream(file);
   //3.加缓冲的效果  BufferedOutputStream
   BufferedOutputStream bos = new BufferedOutputStream(fos);
   //4.声明一个字符串
    String str = "abcdefg";
    bos.write(str,0,str.length);
    bos.close();
    fos.close();
}    

简写:
BufferedOutputStream bos = new BufferedOutputSTream("D:/aaa/1.txt");

针对于上面讲的写一个案例:

​ c:/bbb下面有一个视频文件 复制到c:/aaa下面

使用Java代码

思路: 先从磁盘读取到内存缓冲数组(输入流)中然后再写入磁盘中(输出)

public static void main(String[] args) throws IOException {
        copyVideo1();
    }
    public static void copyVideo () throws IOException {
        //创建缓冲输入流对象
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("c:/bbb/12转义字符.mp4")));
        //创建缓冲输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("c:/aaa/sb.mp4")));
        //准备一个缓冲数组
        byte[] buf = new byte[4096];
        int length;
        while ((length = bis.read(buf)) != -1) {//length = bis.read(buf)  从磁盘读取数据到缓冲数组中
            bos.write(buf, 0, length);//从缓冲数组中写入到磁盘
        }
        bos.close();
        bis.close();
    }

 //不带缓冲的
    public static void copyVideo1 () throws IOException {
       FileInputStream fis = new FileInputStream(new File("c:/bbb/12转义字符.mp4"));
       FileOutputStream fos = new FileOutputStream(new File("c:/aaa/2b.mp4"));
       int length;
       while ((length = fis.read()) != -1) {
            fos.write(length);
       }
       fos.close();
       fis.close();

    }

}

3.3字符输入流

FileReader

将磁盘中的文件的内容读取到Java代码中

阅读字符文件的便利类

FileReader是用于读取字符流。 要读取原始字节流(图片 音频 视频),请考虑使用FileInputStream

FileReader是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符

  public static void main(String[] args) throws IOException {
	//1.创建file对象
    File file  = new File("c:/aaa/1.txt");
    FileReader fr = new FileReader(file);
    BufferedReader br = new BufferedReader(fr);
    char[] cbuf = new char[2];
    int length;
  	while((length = br.read(cbuf)) != -1){
          System.out.println(new String(cbuf,0,length));
      }
    br.close();
    fr.close();
    
}  

3.4字符输入流

FileWriter

场景: Java中有一个字符串然后写入到磁盘的一个文件中

public static void main(String[] args) throws IOException {
	File file  = new File("c:/aaa/1.txt");
    FileWriter fw = new FileWriter(file,true);
    BufferedWriter bw = new BufferedWriter(fw);
    String str = "abcdefg";
    bw.write(str);
    bw.close();
    fw.close();
}    

复制一个文本文档到另外一个盘符下面

 public static void main(String[] args) throws IOException {
        //字符流将一个文本赋值2到另外一个文件夹下面
        //BufferedReader  专门将文本内容读取到内存中
        BufferedReader br = new BufferedReader(new FileReader("c:/bbb/《雪中悍刀行》.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("c:/aaa/88.txt"));
        char[] cbuf= new char[1024];
        int length;
        while ((length = br.read(cbuf)) != -1) {
            bw.write(cbuf, 0, length);
        }
        bw.close();
        br.close();
    }
总结:
	1.输入流和输出流的功能
		输入流:  从磁盘到内存(Java代码)
		输出流:  从内存(java 代码)到磁盘
	2.输入流
		分为两种:
			字节输入流
				FileInputSrteam 
			字符输入流
				FileReader
				核心方法:  read
				
			关于效率问题,他们两个有对应的缓冲流
				FileInputSrteam 对应的BufferedInputStream
				FileReader 对应的 BufferedReader
	3.输出流
		分为两种:
			字节输出流:
				FileOutputStream
			字符输出流:
				FileWriter
					核心的方法 write
			关于效率问题,他们两个有对应的缓冲流
			FileOutputStream对应的缓冲流 BufferedOutputStream 
			FileWriter对应缓冲流   BufferedWriter
	4.记住一句话 用字节流	

五.序列化和反序列化

新建类然后创建对象,然后对对象的属性赋值。对象真实存在了,然后可以通过流来将对象存到本地磁盘上面,这就叫序列化。 本次磁盘上面存的有对象的数据,咱们可以再通过流读取到Java代码中变成对象

这叫反序列化 持久性操作

从内存到磁盘 序列化 输出流 ObjectOutputStream write

class Employee implements Serializable{
    String name;
    int age;
    transient  int ID;//短暂的  此属性不可序列化
    String adress;//地址
    public void eat(){
        System.out.println("今天中午很开心");
    }
}
public class Xuliehua {
    public static void main(String[] args) throws IOException {
        ArrayList arrayList = new ArrayList();
        Employee employee = new Employee();
        employee.name = "gousheng";
        employee.adress = "航海中路";
        employee.age = 18;
        employee.ID = 8989;
        File file = new File("D:/aaa/1.ser");
        FileOutputStream fos = new FileOutputStream(file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(employee);
        oos.close();
        fos.close();
    }
}
class Employee implements Serializable{
    String name;
    int age;
    transient  int ID;//短暂的  此属性不可序列化
    String adress;//地址
    public void eat(){
        System.out.println("今天中午很开心");
    }
}
public class Xuliehua {
    public static void main(String[] args) throws IOException {
        ArrayList arrayList = new ArrayList();
        Employee employee = new Employee();
        employee.name = "gousheng";
        employee.adress = "航海中路";
        employee.age = 18;
        employee.ID = 8989;
        File file = new File("D:/aaa/1.ser");
        FileOutputStream fos = new FileOutputStream(file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(employee);
        oos.close();
        fos.close();
    }
}

反序列化 从磁盘到 内存中 inputStream

public class Fanxuliehua {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream("D:/aaa/1.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Employee emp =(Employee)ois.readObject();
        System.out.println(emp.name);
        System.out.println(emp.age);
        System.out.println(emp.adress);
        System.out.println(emp.ID);//0
    }
}


注意事项:
请注意,一个类的对象要想序列化成功,必须满足两个条件:

该类必须实现 java.io.Serializable 接口。

该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的

六.常用类

1.StringBuffer

描述:
线程安全,可变的字符序列。 字符串缓冲区就像一个String,但可以修改。 在任何时间点,它包含一些特定的字符序列,但可以通过某些方法调用来更改序列的长度和内容。
    
构造方法:
StringBuffer sb = new StringBuffer("abc");"abc“ 0x007
sb.append("ef");      字符串变成  "abcef"  0x007   

方法::
	append("a");	//追加
	insert(2,"b")	//指定位置添加
    delete(2,4)		//从指定位置删除
package com.qf.a_stringbuffer;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
public class Demo1 {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("abcdef");
        System.out.println(sb);
        //System.out.println(sb.toString());//将StringBuffer类型的数据转为String
        sb.append("a");//追加   abcdtrue
        sb.insert(2, "狗");
        //ab狗cdefa
        sb.delete(2, 4);//abdefa
        //字符串反转
        System.out.println(sb.reverse());//afedba
        System.out.println(sb);
        System.out.println(sb.capacity());//容量 容量是新插入字符可用的存储量
        StringBuffer sb1 = new StringBuffer();
        System.out.println(sb1.capacity());//16
        sb1.append("12345678912345671");
        System.out.println(sb1.capacity());







    }
}

2.枚举类

Java中有一个特殊的类叫枚举类,一般表示的是常量。
public  static final int A = 23;
枚举就是替换上面常量的写法的!!!!

语法格式:

public enum 枚举类名 {
	各组常量,常量之间使用逗号隔开
}
package com.qf.b_enum;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
enum Color {
    RED, GREEN, BLUE
}
public class Demo1 {
    public static void main(String[] args) {
        Color red = Color.RED;
        System.out.println(red);//RED
    }
}

构造方法

package com.qf.b_enum;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
enum Ball {
    TYPE_BALL_FOOTBALL(1, "足球"),
    TYPE_BALL_PINGPANGBALL(2, "乒乓球"),
    TYPE_BALL_BASEGETBALL(3, "篮球"),
    ;
    int key;
    String name;

    Ball(int key, String name) {
        this.key = key;
        this.name = name;
    }

    public int getKey() {
        return key;
    }

    public void setKey(int key) {
        this.key = key;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Demo3 {
    public static void main(String[] args) {

        Ball.TYPE_BALL_FOOTBALL.setKey(4);
        int key = Ball.TYPE_BALL_FOOTBALL.getKey();
        System.out.println(key);
        String name = Ball.TYPE_BALL_FOOTBALL.getName();
        System.out.println(name);
    }
}

枚举方法

values();  枚举类中的所有的值
oridnal();每个常量的索引值
valueOf();返回值的指定的字符串的常量
package com.qf.b_enum;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
enum Color1 {
    RED, GREEN, BLUE
}
public class Demo4 {
    public static void main(String[] args) {
        Color1[] values = Color1.values();
        for (Color1 value : values) {
            System.out.println(value +"对应的索引:" + value.ordinal() );
        }
        //valueOf();返回值的指定的字符串的常量
        Color1 red = Color1.valueOf("RED");
        System.out.println(red);
    }
}

Java在生产环境中如何使用的

枚举一般在使用的时候确定业务场景的。

支付功能,需要使用以下几种支付的方式:

微信小程序支付 wxma  
微信H5支付    wxh5
支付宝小程序支付  zfbma
支付宝生活号支付  zfbshm
微信医保支付  wxyb

可以使用枚举类来维护这几种支付方式,一旦需要新增,需要修改 需要删除的时候,随时修改枚举类即可

package com.qf.b_enum;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
//支付方式的枚举类
enum PayTypeEnum {
    WEI_XIN_MINI_APP("1", "wxma", "微信小程序支付"),
    WEI_XIN_H5("2", "wxh5", "微信H5支付"),
    ZFB_MINI_APP("3", "zfbma", "支付宝小程序支付"),
    ZFB_SHH("4", "zfbshm", "支付宝生活号支付"),
    WEI_XIN_YB("5", "wxyb", "微信医保支付"),
    ;

    private final String id;
    private final String code;//支付类型码
    private final String type;//支付方式类型

    PayTypeEnum(String id, String code, String type) {
        this.id = id;
        this.code = code;
        this.type = type;
    }

    public String getId() {
        return id;
    }

    public String getCode() {
        return code;
    }

    public String getType() {
        return type;
    }
}
public class Demo5 {
    public static void main(String[] args) {
        //获取枚举类的id‘值
        String id = PayTypeEnum.ZFB_MINI_APP.getId();
        System.out.println(id);

    }
}

package com.qf.b_enum;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
enum SexEnum {
    MALE(0, "男"),
    FEMALE(1, "女"),
    ;
    private int sex;//0代表男 or 1  代表女
    private String sexName;//男 or 女

    SexEnum(int sex, String sexName) {
        this.sex = sex;
        this.sexName = sexName;
    }

    public int getSex() {
        return sex;
    }

    public String getSexName() {
        return sexName;
    }
}
class User {//用户类
    private String name;//用户名字
    private SexEnum sex;//用户的性别

    public String getName() {
        return name;
    }

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

    public SexEnum getSex() {
        return sex;
    }

    public void setSex(SexEnum sex) {
        this.sex = sex;
    }
}
public class Demo6 {
    public static void main(String[] args) {
        User user = new User();
        user.setName("狗蛋");//赋值
        user.setSex(SexEnum.MALE);

        System.out.println(user.getSex().getSexName());



    }
}

3.包装类

Java八大基本数据类型,都有与之对应的包装类

为啥会有这些包装类?其实就代表基本数据类型所有东西

包装类能够实例化处理对象,有很多的方法,来处理当前的数据

这样来操作八大基本数据类型很方便

int==>Integer

byte===>Byte

short====>Short

long====>Long

float====>Float

double====>Double

boolean====>Boolean

char====>Character

【重点】:

​ 1.自从jdk5之后 ,有自动拆箱和自动装箱

​ 自动装箱: 将基本数据类型转为包装类类型

​ 自动拆箱: 将包装类转为基本数据类型

 		2. static String    toString();  将基本数据类型转为 字符串
           		3. static  parse***(); 将一个字符串转为 所对应基本数据类型
package com.qf.c_baozhuang;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
class User {
    String name;
    Integer age;
    String email;
    Integer sex;
}
public class Demo1 {
    public static void main(String[] args) {
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);

        //1.自动装箱:  将基本数据类型转为包装类型
        int i = 30;
        Integer i1 = i;
        System.out.println(i1.hashCode());
        //2.自动拆箱:  将包装类转为基本数据类型
        int i2 = i1;
        System.out.println(i2);


        //3.***Value();
        Integer i3 = 40;//i3是包装类类型的数据
        int i4 = i3.intValue();//intValue
        System.out.println(i4);//i4是基本数据类型
        //shortValue()

        //4.toString方法
        String s = Integer.toString(34);
        System.out.println(s);

        //5将整数字符串转为基本数据类型
        int i5 = Integer.parseInt("999");
        System.out.println(i5);//999
        double v = Double.parseDouble("89.7");

        //

        Integer i6 = 30;
        Integer i7 = 30;
        System.out.println(i6 == i7);//true
        Integer i8 = new Integer(30);
        System.out.println(i6 == i8);
        Integer i9 = 129;
        Integer i10 = 129;
        System.out.println(i9 == i10);//false


    }
}

有兴趣的话,看看Integer的底层

4.Math

Math类包含执行基本数字运算的方法,如基本指数,对数,平方根和三角函数。

package com.qf.d_math;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
public class Demo1 {
    public static void main(String[] args) {
        System.out.println(Math.E);
        System.out.println(Math.PI);

        System.out.println(Math.abs(-89));//求一个数的绝对值  absolute
        System.out.println(Math.max(3, 7));//7   求两个数最大值的
        System.out.println(Math.max(1, Math.max(3, 9)));//9
        System.out.println(Math.min(1, 2));
        System.out.println(Math.ceil(34.5));//向上取整
        System.out.println(Math.floor(34.5));//34.0  向下取整

        System.out.println(Math.round(34.6));//35 long
        System.out.println(Math.random());//double  大于等于 0.0 ,小于 1.0 。
    }
}

5.Random

package com.qf.e_random;

import java.util.Random;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
public class Demo1 {
    public static void main(String[] args) {
        Random random = new Random();
        System.out.println(random.nextInt());
        System.out.println(random.nextBoolean());
        System.out.println(random.nextInt(3));
        System.out.println(random.nextDouble());
    }
}

6.System

System类提供的System包括标准输入,标准输出和错误输出流; 访问外部定义的属性和环境变量; 一种加载文件和库的方法; 以及用于快速复制阵列的一部分的实用方法。

package com.qf.f_system;

import java.io.PrintStream;
import java.util.Properties;
import java.util.Scanner;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
public class Demo1 {
    public static void main(String[] args) {
        PrintStream out = System.out;//标准输出
        out.println("hehe");
        System.out.println("xiix");
        Scanner scanner = new Scanner(System.in);
        //m	err
        //“标准”错误输出流。
        System.err.println("haha");

        //返回当前的时间
        long l = System.currentTimeMillis();   //ms
        System.out.println(l);//1680076586166
        //在1970年1月1日UTC之间的当前时间和午夜之间的差异,以毫秒为单位。

        //通过类 获取当前系统的一个属性
        Properties properties = System.getProperties();
        System.out.println(properties.get("os.name"));//Windows 10
        System.out.println(properties.get("user.name"));//bowang
        System.out.println(properties.get("java.version"));//1.8.0_241
    }
}

7.Date

专门处理时间的一个类

package com.qf.g_date;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
public class Demo1 {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date);
        //Wed Mar 29 16:17:57 IRKT 2023
        //我难受 看不懂? 吧咋办? 转成你能看懂的   格式化
        //SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期
        //SimpleDateFormat(String pattern)
        //使用给定模式 SimpleDateFormat并使用默认的 FORMAT语言环境的默认日期格式符号。
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println(format);
    }
}

package com.qf.g_date;

import java.util.Calendar;
import java.util.Date;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
public class Demo2 {
    public static void main(String[] args) {
        Date date = new Date();
        //返回一个值,该值是从包含本开始时间的年份中减去1900的值
        System.out.println(date.getYear() + 1900);
        //返回一个数字,表示包含或开始于此Date对象所代表的时刻的月份 。 返回的值在0和11之间,其值为0代表一月。
        System.out.println(date.getMonth() + 1);//2


        //返回由此日期表示的星期几。 返回值( 0 =星期日, 1 =星期一, 2 =星期二, 3 =星期三, 4 =星期四, 5 =星期五, 6 =星期六)表示包含或以此时间表示的时刻开始的星期几Date对
        System.out.println(date.getDay());//3

        Calendar rightNow = Calendar.getInstance();//获取日历的对象
        System.out.println(rightNow);

        System.out.println(rightNow.get(Calendar.YEAR));//2023
        System.out.println(rightNow.get(Calendar.MONTH) + 1);//3
        System.out.println(rightNow.get(Calendar.DAY_OF_MONTH));//29
        System.out.println(rightNow.get(Calendar.DAY_OF_YEAR));//88
        System.out.println(rightNow.get(Calendar.DAY_OF_WEEK) - 1);//4
        System.out.println(rightNow.get(Calendar.HOUR));//4  pm
        System.out.println(rightNow.get(Calendar.HOUR_OF_DAY));//16





    }
}

两个类:

BigDecimal
LocalDate

七.进程 线程

1.进程线程并行并发概念

进程概念:

​ 1.独立性

​ 每个进程之间是相互独立的,互不影响的.

​ 2.互斥性

​ 每个应用程序(软件)系统分配一个独立的端口号. 不能重复

线程概念:

​ 进程是由至少一个或着多个线程组成的.

​ 线程是进程最小的基本单位.

特性:

​ 1.抢占式运行

​ 给程序分配CPU, 按照时间片来执行, 单位时间片抢占式执行,随机抢占.

​ 2.资源共享

​ 同一个进程, 有多个线程, 这个多线程是可以共享同一个数据的.

并行和并发

并行:真正的同时执行
并发:同时发生,轮流交替执行

2.创建线程的两种方式

Java虚拟机允许应用程序同时执行多个执行线程。

方法1:
	创建一个新的执行线程有两种方法。 一个是将一个类声明为`Thread`的子类。 这个子类应该重写`run`方法`Thread` 。 然后可以分配并启动子类的实例。
  	1.声明一个类继承Thread
    2.重写run方法
    3.新建线程的实例
    4.start()启动线程
        
class A extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            System.out.println("A线程:"+i);
        }
    }
}
class B extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            System.out.println("B线程:"+i);
        }
    }
}
public class Xiancheng {
    public static void main(String[] args) {
        new A().start();
        new B().start();
        for (int i = 0; i < 101; i++) {
            System.out.println("主线程:"+i);
        }
    }
}
方法2:
	另一种方法来创建一个线程是声明实现类`Runnable`接口。 那个类然后实现了`run`方法。 然后可以分配类的实例,在创建`Thread`时作为参数传递,并启动。 
    1.声明一个类实现Runnable
    2.重写run方法
    3.新建线程的实例
    4.传参给新建Thread实例
   	5.start()启动线程

class C implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            System.out.println("C线程:"+i);
        }
    }
}
class D implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            System.out.println("D线程:"+i);
        }
    }
}
public class Xiancheng2 {
    public static void main(String[] args) {
        C c = new C();
        new Thread(c).start();
        new Thread(new D()).start();
        for (int i = 0; i < 101; i++) {
            System.out.println("主线程:"+i);
        }

    }
}

3.Thread线程方法

Thread构造方法:

方法1无参构造:
Thread t = new Thread();

方法2分配一个新的Thread对象:
Thread t = new Thread(new 类名());

方法3分配一个新的Thread对象. 并对这个线程起一个名字
Thread t = new Thread(new 类名(),"线程名字") 
Thread方法:
     .currentThread()//返回当前正在执行的线程对象的引用
     .getName()//返回此线程的名称
     .setName(String name)//将此线程的名称更改为参数name
     .getPriority()//返回此线程的优先级
     .setPriority()//更改此线程的优先级
Thread.sleep(long millis)//使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。需要try,catch

4.线程同步和锁

当多个线程同时请求一个数据的时候,会导致数据不准确的情况。相互之间产生问题。容易出现线程安全的问题。比如多个线程操作同一个数据,都打算修改商品库存。

线程的同步真实的意思: 让你"排队",几个线程之间要排队。一个一个对共享资源进行操作,等一个结束以后,另外一个再进来操作。变量 是唯一的和准确的

可以加锁

synchronized 隐式锁,会自动释放,一个非公平的锁。
    
方法1:
同步方法:
public synchronized void run(){

}
只能有一个线程进入到方法中,其他线程在方法的外面等待
弊:太极端,一个线程执行完.
方法2:
同步代码块:  将一段代码放到synchronized   然后括起来。就会对这段代码加上锁。
sychronized(this){
    
}


class E implements Runnable{
    private int length = 100;
    @Override
    public  void run() {
        while(true){
            synchronized (this){
            if (length > 0){              System.out.println(Thread.currentThread().getName()+ "卖出了第" + length-- +"票");
            }else {
                System.out.println("售空");
                break;
            }
        }
        }
    }
}
public class Shuo1 {
    public static void main(String[] args) {
        E e = new E();
        new Thread(e,"窗口1").start();
        new Thread(e,"窗口2").start();
    }
}

要求不能使用同步代码块来解锁,必须使用同步方法来加锁 来实现上面的案例

class E implements Runnable{
    private int length = 100;
    @Override
    public  void run() {
        while(true){
            test();
            if (length <= 0){
                break;
            }
        }
    }
    public synchronized void test(){

            if (length > 0){              System.out.println(Thread.currentThread().getName()+ "卖出了第" + length-- +"票");
            }else {
                System.out.println("售空");
                return;
        }
    }
}
public class Shuo1 {
    public static void main(String[] args) {
        E e = new E();
        new Thread(e,"窗口1").start();
        new Thread(e,"窗口2").start();
    }
}

5.Java中的锁

synchronized 被成为隐式锁,会自动释放,式一个非公平的锁。

Lock锁 被成为显示锁。

他们两个锁都可以解决线程同步的问题。但是synchronized 更加强大,更加粒度化。更加灵活。

所以一般开发时候用synchronized 。以后还会有线程池,也有锁 更高级。

Lock是一个接口,实现ReentrantLock

有两个重要方法:

​ lock();

​ unlock();

不安全

class F implements Runnable{
    private  int ticket = 100;
    ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while(true){
            try{
                lock.lock();
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName()+ "卖出了第" + ticket-- +"票");
                }else{
                    System.out.println("售空");
                    break;
                }
            }catch (Exception e) {

            } finally {
                lock.unlock();
            }

        }
    }
}
public class Shuo2 {
    public static void main(String[] args) {
        new Thread(new F(),"线程1").start();
        new Thread(new F(),"线程2").start();
    }
}

6.守护线程【了解】

守护线程是用来守护非守护线程的

class E implements  Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("守护线程:" + i);
        }
    }
}

public class Demo3 {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.isDaemon());//false  非守护线程
       // thread.setDaemon(true);//设置为守护线程
        Thread thread1 = new Thread(new E());
        //System.out.println(thread1.isDaemon());
        thread1.setDaemon(true);
        thread1.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("主线程:" + i);
        }
    }
}

八.死锁

1.死锁

开发中禁止出现死锁

面试会问:

​ 应用场景: 并发场景,多个线程。线程之间在共享数据的时候 是互不相让的

线程加锁为了线程安全,但是物极必反。

死锁是一种状态,当两个线程互相持有对象所需要的资源的时候,这两个线程又都不主动释放资源

就会导致死锁。代码无法正常执行。这两个线程就会僵持住。

package com.qf.a_sisuo;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
class DeadLock implements Runnable {
    private boolean flag;//标记
    private Object obj1;//对象1
    private Object obj2;//对象2

    public DeadLock(boolean flag, Object obj1, Object obj2) {
        this.flag = flag;
        this.obj1 = obj1;
        this.obj2 = obj2;
    }

    @Override
    public void run() {
        if (flag) {//如果flag = true 让线程1执行这个if语句里面的代码
            synchronized (obj1) {
                System.out.println(Thread.currentThread().getName() + "拿到了obj1资源");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程1执行了");
                synchronized (obj2) {//想用obj2这个资源
                    System.out.println(Thread.currentThread().getName() + "拿到obj2资源");
                }
            }
        }
        if (!flag) {//如果flag=false 线程2 执行这个if语句里面的代码
            synchronized (obj2) {
                System.out.println(Thread.currentThread().getName() + "拿到了obj2资源");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程2执行了");

                synchronized (obj1) {
                    System.out.println(Thread.currentThread().getName() + "拿到obj1资源");
                }
            }

        }
    }
}
public class Demo1 {
    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();
        DeadLock deadLock1 = new DeadLock(true, obj1, obj2);
        new Thread(deadLock1, "线程1").start();
        DeadLock deadLock2 = new DeadLock(false, obj1, obj2);
        new Thread(deadLock2, "线程1").start();
    }
}

2.Object类下面的和线程相关的方法

public final void wait()
          throws InterruptedException

导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。

总结: 至少两个线程, 对象.wait() ,那么当前线程就会等待。

wait1线程正在等待中....
唤醒线程已经执行
wait1线程被唤醒!!!Line45行的
我是修改之后的message对象
wait2线程正在等待中....

package com.qf.b_object;

/**
 * description:
 * 公司:千锋教育
 * author:博哥
 * 公众号:Java架构栈
 */
//为啥写Message这个类?  wait方法    对象.wait(); 创建Message对象
    //
class Message {
    private String message;//信息

    public Message(String message) {
        this.message = message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

}
//线程类  等待线程
class WaitThread implements Runnable {
    private Message message;

    public WaitThread(Message message) {
        this.message = message;
    }
//等待线程抢到了
    //等待线程睡了5秒  然后唤醒线程执行。  synchronized (message)
    //message  对象从等待池中国去取的,结果发现没有  阻塞
    //回到等待线程睡醒了以后开始   wait等待

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + "正在等待中....");

        synchronized (message) {
            try {

                //当调用wait方法的时候,会自动释放锁,并将对象放到等待池中,让唤醒线程锁来操作这个对象
                //
                message.wait();//代码走到这一步 当前线程会等待!!!
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name +"被唤醒!!!Line45行的");
            System.out.println(message.getMessage());
        }
    }
}
//唤醒线程
class NotifyThread implements Runnable {
    private Message message;

    public NotifyThread(Message message ) {
        this.message = message;
    }
    @Override public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("唤醒线程已经执行");
       synchronized (message) {
            message.setMessage("我是修改之后的message对象");
            //message.notify();
            message.notifyAll();

       }
    }
}
public class Demo1 {
    public static void main(String[] args) {
        Message message = new Message("我是message对象");
        WaitThread waitThread = new WaitThread(message);
        WaitThread waitThread1 = new WaitThread(message);
        NotifyThread notifyThread = new NotifyThread(message);

        new Thread(waitThread1, "wait2线程").start();
        new Thread(waitThread, "wait1线程").start();
        new Thread(notifyThread, "notify线程").start();

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值