JAVA基础

JAVA流程控制

Scanner

next()方法

  1. 一定要读取到有效字符后才可以结束输入。
  2. 对输入有效字符之前遇到的空白,next()方法会自动将其去掉
  3. 只有输入有效字后才将其后面输入的空白作为分隔符或者结束符。
  4. next() 不能得到带有空格的字符串
Scanner scanner = new Scanner(System.in);

System.out.println("请输入内容");	//输入内容:hello word
if (scanner.hasNext()){                 //判断用户有没有输入   循环会用到现在用不到
    String s = scanner.next();          //使用next方法接收
    System.out.println(s);		   // = hello
}
scanner.close();                    	//属于IO流的如果不关闭回一直占用资源

nextLine()方法

  1. 以Enter为结束符,也就是说NextLine()方法返回的时输入回车之前的所有字符。
  2. 可以获得空白。
Scanner scanner = new Scanner(System.in);

System.out.println("请输入内容");   //输入内容:hello word
if (scanner.hasNextLine()){                 //判断用户有没有输入    循环会用到
    String s = scanner.nextLine();          //使用nextLine方法接收
    System.out.println(s);       // = hello word
}
scanner.close();                       //属于IO流的如果不关闭回一直占用资源

检测输入类型

Scanner scanner = new Scanner(System.in);
if (scanner.hasNextInt()){
    System.out.println("数字");
}else if (scanner.hasNextDouble()){
    System.out.println("小数");
}else if (scanner.hasNextLine()){
    System.out.println("字符");
}else {
    System.out.println("s");
}
scanner.close();

限定输入类型while

Scanner scanner = new Scanner(System.in);
double sum = 0;         //计算输入的总和
int m = 0;				//计算输入了多少次

while (scanner.hasNextDouble()){            //判断输入是否为double型 如果输入字符串就结束循环
    double x = scanner.nextDouble();
    m = m+1;
    sum = sum + x;
    System.out.println("m:"+m+"  sum:"+sum);
}
scanner.close();

if选择结构

int s = 10;
if (s == 10){
    System.out.println("s=10");
}else if (s == 20){
    System.out.println("s=20");
}else {
    System.out.println("s=不知道");
}

switch选择结构

//JDK7以后可以用字符串

char grade = 'a';
switch (grade){
    case 'A':
        System.out.println("优秀");
        break;
    case 'B':
        System.out.println("良好");
        break;
    default:
        System.out.println("未知等级");
}

循环结构

while循环

  • 只要布尔表达式为true,循环就会一直执行下去
while (布尔表达式){
    
}
do while循环
  • do while 循环和while类似 不同的是do while循环至少会执行一次
  • do while 循环是先循环在判断
do {
    
}while (布尔表达式);

For循环

for (int i=初始值;i<=最大值;i++更新){
    
}

九九乘法表

for (int j=1;j<=9;j++){
    for (int i= 1;i<=j;i++){
        System.out.print(j+"*"+i+"="+(j*i)+"\t");
    }
    System.out.println();
}
增强for循环
int[] number = {10,20,30,40,50};

for (int x : number){
    System.out.println(x);
}

break、continue、goto

  • break: 在任何循环语句的主体部分,均可用break控制循环的流程。用于强行退出循环,不执行循环中剩余语句。

  • continue:用于在循环语句体中。用于终止某次循环过程,跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定

  • goto: 标签

    outer:for (int i=101;i<150;i++){
        for (int j=2;j<i/2;j++){
            if (i%j == 0)
            continue outer;
        }
        System.out.println(i+"");
    }
    

方法

    public static void main(String[] args) {
        max(12,32);
    }

    private static int max(int num1, int num2) {
        int s = 0;
        if (num1 == num2) {
            System.out.println("num1=num2");
            return 0;           //return 0;  	终止方法
        }
        if (num1>num2){
            s = num1;
        }else {
            s = num2;
        }
        System.out.println(s);
        return s;
    }

break return区别

return : 结束方法返回一个结果

break :跳出

调用方法

public static void main(String[] args) {
    Demo demo = new Demo();
    System.out.println(demo.syHello());
}

public String syHello(){
    return "Hello";
}

可变参数方法

public static void main(String[] args) {

    test(1,2,3,4,5,6,7);

}

public static void test(int... i){
    int s = i.length;
    for (int i1 = 0; i1 < i.length; i1++) {
        System.out.println(i[i1]);
    }
}

递归

public static void main(String[] args) {	
    System.out.println(f(5));			//==120
}
public static int f(int n){				//= 5*4*3*2*1 = 120
    if (n==1){
        return 1;
    }else {
        return n*f(n-1);
    }
}

数组

int[] a = {1,2,3};  	//静态初始化  

arr = new int[3];   //创建一个数组		动态初始化
arr[0] = 12;        //给0号赋值1
arr[1] = 22;        //给1号赋值1
arr[2] = 32;        //给2号赋值1

System.out.println(arr.length);		//数组的长度

for (int i = 0; i < arr.length; i++) {      //打印数组数据
    System.out.println(arr[i]);
}

数组类

public static void main(String[] args) {
    Man[] men = {new Man(),new Man()};
}
static class Man{ 
}

for-Each

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

数组反转

public static void main(String[] args) {
    int[] a = {1,2,3};
    reverse(a);
}

private static int[] reverse(int[] a) {
    int [] result = new int[a.length];
    for (int i=0,j=result.length-1;i<a.length;i++,j--){
        result[j] = a[i];
    }
    for (int i = 0; i < result.length; i++) {
        System.out.println(result[i]);
    }
    return result;
}

二维数组

int [][] arr = {{1,2},{2,3},{3,4}};
	System.out.println(arr[1][0]); 		//=2
	System.out.println(arr[1][1]); 		//=3
    System.out.println(arr.length);     //=3
    System.out.println(arr[0].length);  //=2

for (int i=0;i< arr.length;i++){
    for (int j=0;j<arr[i].length;j++){
        System.out.println(arr[i][j]);
    }
}

打印数组Arrays类

int[] a = {1,2,3,4,512,134,123};
System.out.println(Arrays.toString(a));	// = [1, 2, 3, 4, 512, 134, 123]

int[] a = {1,2,3,4,512,134,123};
Arrays.fill(a,1);                // = [1, 1, 1, 1, 1, 1, 1]			   数组所有内容填充1
Arrays.fill(a,2,4,1);   		 // = [1, 2, 1, 1, 512, 134, 123]      2-4数组被填充为1
System.out.println(Arrays.toString(a));		//打印数组

冒泡排序

public static void main(String[] args) {
    int[] arr = {2,3,12,3,13,342};
    sort(arr);
    System.out.println(Arrays.toString(arr));
}
public static int[] sort(int[] array){
    int temp = 0;
    for (int i = 0; i <array.length-1; i++) {
        for (int j=0;j<array.length-1;j++){		
            if (array[j+1]>array[j]){		  //if (array[j+1]>array[j]) 由大到小排序
                temp = array[j];			  //if (array[j+1]<array[j]) 由小到大排序
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
    return array;
}

优化过

public static void main(String[] args) {
    int[] arr = {2,3,12,3,13,342};
    sort(arr);
    System.out.println(Arrays.toString(arr));
}

public static int[] sort(int[] array){
    int temp = 0;
    for (int i = 0; i <array.length-1; i++) {
        boolean flag = false;
        for (int j=0;j<array.length-1;j++){
            if (array[j+1]<array[j]){
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
                flag = true;
            }
        }
        if (flag == false){
            break;
        }
    }
    return array;
}

稀疏数组

int [][] arr1 = new int[11][11];		//创建一个11行11列的数组
arr1[1][2] = 1;							//在第1行第2列插入1
arr1[2][3] = 2;							//在第2行第3列插入2
for (int[] ints : arr1) {				//将所有值打印出来
    for (int anInt : ints) {
        System.out.print(anInt+"\t");
    }
    System.out.println();
}

int s = 0;
for (int i = 0; i < arr1.length; i++) {			//找出不为0的数组有多少个
    for (int i1 = 0; i1 < arr1.length; i1++) {
        if (arr1[i][i1] !=0){
            s++;
        }
    }
}
System.out.println("有效值的个数"+s);

面向对象

方法

实例化类

public static void main(String[] args) {
    Student student = new Student();		//实例化这个类  通过new出来
    student.say();							//对象类型  对象名 = 对象值
}

public class Student {
    public void say(){
        System.out.println("学生");
    }
}

static

加上静态变量可以直接用类名调用

没加静态 必须 new

静态方法和类一起加载 非静态方法必须调用

public class Demo {

    public static void main(String[] args) {
        a();					//方法a可以直接调用
        Demo demo = new Demo();	
        demo.b();				//方法b要通过创建对象的方法才可以使用
    }
    
    public static void a(){		//加上static当创建Demo的时候就已经加载了

    }
    public void b(){			//不加static 必须通过 new 调用的方式加载

    }
}
public class Demo {
    
    {               //2运行
        System.out.println("匿名代码块");
    }
    
    static {        //首先运行					//只会再创建的时候执行一次
        System.out.println("静态代码块");
    }

    public Demo() { //3 构造方法
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Demo demo = new Demo();				//=静态代码块
    }										//匿名代码块
}											//构造方法

引用传递:

public class Demo {

    public static void main(String[] args) {
        Stud stud = new Stud();
        System.out.println(stud.name);		//=s
        Demo.change(stud);
        System.out.println(stud.name);		//=123
    }
    public static void change(Stud stud){
        stud.name = "123";
    }
}

class Stud{
    String name = "s";
}

构造器

public static void main(String[] args) {

    Student student = new Student();		//无参构造	会调用Student的方法如果没有会自动生成一个无参方法
    System.out.println(student.string);		//= guan

    Student student1 = new Student("xin");	//有参构造
    System.out.println(student1.string);	//= xin
    
}

public class Student {

    public String string;

    public Student() {
        this.string = "guan";
    }

    public Student(String string) {
        this.string = string;
    }
}

继承

每个类默认继承Object的类只是隐藏了

子类继承父类的所有方法,父类的private子类不可以调用

创建对象

--------Teacher
public class Teacher {
    public Teacher(){
        System.out.println("Teacher");
    }
}

--------Student
public class Student extends Teacher{
    public Student(){						
        System.out.println("Student");		//创建方法时也会调用父类的方法  会有一个隐藏的super()对象  不能使用this
    }
}

--------Demo
public class Demo {
    public static void main(String[] args) {
        Student student = new Student();       //=  Teacher		先调用父类再调用子类	
											   //	Student
    }
}

子类方法和父类方法调用

------Teacher
public class Teacher {

    public void show(){
        System.out.println("sss");
    }

}
-----Student
public class Student extends Teacher{

    public String name = "wo";

    public void stud(){
        System.out.println("xuesheng");
    }

}
------Demo
public class Demo {

    public static void main(String[] args) {

        Student student = new Student();
        student.stud();
        student.show();
        System.out.println(student.name);

    }

}

Super

super可以强制调用父类的方法 重名可以

注意点:

  • super调用父类的构造方法,必须再构造方法的第一个
  • suiper必须再子类的方法或者构造方法中
  • super 和 this 不能同时调用
-----Teacher
public class Teacher {

    public String name = "guangxin";

}
--------Student
public class Student extends Teacher{

    private String name = "guan";

    public void test(String name){
        System.out.println(name);			//调用方法里的属性				= guan1
        System.out.println(this.name);		//加this = 调用类里面的属性	   = guan
        System.out.println(super.name);		//supoer = 调用父类的属性		= guanxin
    }

}
------Demo
public class Demo {
    public static void main(String[] args) {
        Student student = new Student();
        student.test("guan1");				//调用子类的test方法
    }
}

super与this 构造方法

代表的对象不同

  • this :本身调用者这个对象
  • super:代表父类对象的应用

前提

  • this:没有继承也可以使用
  • super: 只有继承才可以使用

构造方法

  • this : 本类的构造
  • super:父类的构造

加上静态方法

加上静态可以直接用类名调用 B.test();

public class B {

    public static void test(){
        System.out.println("B_test");
    }

}
public class A extends B{

    public static void test(){
        System.out.println("A_test");
    }

}

    public static void main(String[] args) {
        A a = new A();
        a.test();			// = A_test    调用A类的静态方法
        A.test();			// = A_test
        B b = new A();						//父类的引用指向子类
        b.test();			// = B_test
    }

重写

父类的静态方法不能被重写

b是A new 出来的对象,因此调用了A方法没有static时,b调用的时对象的方法,而b时用A类new的

因为静态方法时类的方法 ,而非静态是对象的方法

有static时 b调用了B的类的方法 因为b是b类定义的

子类方法和父类的方法必须一致 方法体不同

修饰符

可以扩大但是不能缩小 public > protected > private

public class B {

    public void test(){
        System.out.println("B_test");
    }
    
    protected void ts(){
        System.out.println("B");
    }
}

public class A extends B{

    //Override  重写		
    @Override       //注解:有功能的注释
    public void test() {
        System.out.println("A");		//重写test方法会有 super.test(); 方法 删了重写就会调用子类的方法了
    }
    
   @Override
    protected void ts() {
        System.out.println("AA");		//重写父类的ts方法  
    }
    
}

    public static void main(String[] args) {
        A a = new A();		
        a.test();			//=A

        B b = new A();					//子类重写了父类的方法
        b.test();			//=A
        b.ts();				// = AA
    }

多态

子类调用的方法都是自己的 或者继承父类的

父类可以指向子类 但是不能调用子类独有的方法

public class Person {

    public void run(){
        System.out.println("run");
    }
}

public class Student extends Person {

    public void eat(){
        System.out.println("ear");
    }

}
    public static void main(String[] args) {
        Student s1 = new Student();
        Person s2 = new Student();
        s1.eat();       				// = ear  子类调用的方法都是自己的 或者继承父类的
        ((Student) s2).eat();      		// = ear  父类可以指向子类 但是不能调用子类独有的方法		只能强转成子类
    }

instanceof

instanceof判断类型是否相似

父类引用指向子类对象

把子类转成父类,向上转型

把父类转换子类,向下转型 : 强制转换

----Teacher
public class Teacher extends Person{

}
----Person
public class Person {

}
----Student
public class Student extends Person {

}

    public static void main(String[] args) {
        Object object = new Student();     //终极父类
        System.out.println(object instanceof Student); //= true
        System.out.println(object instanceof Person);  //= true
        System.out.println(object instanceof Object);  //= true
        System.out.println(object instanceof Teacher); //= false  因为Teacher跟Student无关
        System.out.println(object instanceof String);  //= false
        
        Person object1 = new Student();     //终极父类
        System.out.println(object1 instanceof Student); //= true
        System.out.println(object1 instanceof Person);  //= true
        System.out.println(object1 instanceof Object);  //= true
        System.out.println(object1 instanceof Teacher); //= false  因为Teacher跟Student无关
        //System.out.println(object1 instanceof String);  //= false 编译报错
        
        Student student = new Student();
        System.out.println(student instanceof Student); //= true
        System.out.println(student instanceof Person);  //= true
        System.out.println(student instanceof Object);  //= true
        //System.out.println(student instanceof Teacher); //= false  编译报错
        //System.out.println(object1 instanceof String);  //= false 编译报错
    }

抽象类abstract

继承抽象类必须实现抽象类里面的所有方法

继承只能单继承 接口 可以多继承

抽象类不能new出来只能靠子类去实现他

实现抽象类
----Action
public abstract class Action {
    public abstract void doSomething();    //只有抽象方法名字 没有方法实现    在调用方法里面实现
}

public class Demo extends Action{			//抽象类的所有方法,继承了他的子类都必须要实现他的方法
    
    public static void main(String[] args) {
       Demo demo = new Demo();			
       demo.doSomething();					// = ss
    }

    @Override
    public void doSomething() {
        System.out.println("ss");
    }
}
实现抽象的子子类
----Action
public abstract class Action {
    public abstract void doSomething();    //只有抽象方法名字 没有方法实现    在调用方法里面实现
}
----Person
public abstract class Person extends Action{         //抽象类的所有方法继承了他的子类必须要实现他的方法  除非子类也是一个抽象方法
    public abstract void show();
}
----Demo
public class Demo extends Person{			//继承Person时就要实现父类Person的所有方法和Action的所有方法
    @Override
    public void doSomething() {
        
    }

    @Override
    public void show() {

    }
}

通过new抽象类
----Action
public abstract class Action {

    public abstract void doSomething();    //只有抽象方法名字 没有方法实现    在调用方法里面实现

}
----
    public static void main(String[] args) {

        Action s = new Action() {
            @Override
            public void doSomething() {
                System.out.println("s");	//实现抽象类
            }
        };							
        s.doSomething();					//调用抽象类

    }

方法2

new Action() {						//也可以通过这种方法调用
    @Override
    public void doSomething() {		//实现抽象方法
        System.out.println("s");
    }
}.doSomething();					//调用抽象类

interface接口

作用

  1. 约束
  2. 定义一些方法让不同的方法让不同的人实现
  3. 接口不能实例化接口没有构造方法
  4. implements可以实现多个接口
----UserService
public interface UserService {          //接口中所有定义都是抽象的
    //public abstract void run();  接口中默认都是 public abstract   所不用写
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
----TimeService
public interface TimeService {
    void time();
}
----UserServiceImpl   //实现接口的所有方法  一般都用Impl结尾
public class UserServiceImpl implements UserService,TimeService{         
    //实现接口的类就需要重写接口中的方法
    //可以实现多继承
    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void time() {

    }
}
----Main方法
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();		//直接new出对象就可以使用了
        userService.add("1");
        userService.delete("1");
    }

内部类

----Demo
public class Demo {

    private int id = 1;

    public void out(){
        System.out.println("外部类的方法");
    }

    public class Inner{
        public void in(){
            System.out.println("内部类");
        }
        public void getID(){
            System.out.println(id);
        }
    }
}
-----Test
public class Test {
    public static void main(String[] args) {
        Demo demo  = new Demo();
        demo.out();     // = 外部类的方法

        Demo.Inner inner = demo.new Inner();
        inner.getID();
        inner.in();
    }
}
public class Test {

    public static void main(String[] args) {
        new Apple().eat();
        new UserService(){
            @Override
            public void hello() {

            }
        };
    }
}

class Apple{
    public void eat(){
        System.out.println("1");
    }
}
interface UserService{
    void hello();
}

Object

java中所有类都要继承Object

Object是一个类,也是所有类的根

我们写的类即使不写继承关系,那么也会继承Object

equals和==

判断左右两端的数据是否一致

字符串的判断一定要用equals

== 判断内存地址

toString方法

默认的toString是Object的方法 (包名+类名+@内存地址)

直接调用bean文件的toString方法 目录会以默认的地址 所以要在子类里重写toString方法

instanceof

可以判断两个对象是不是一个类型的

public class Test {
}


public  class Demo extends Test{
    
    public static void main(String[] args) {

        Test test = new Demo();		
        if (test instanceof Demo){
            System.out.println("y");
        }else {
            System.out.println("s");
        }
        // = y    是一个类型的
    }
}

----------------------------
public class Test {
}


public  class Demo extends Test{
    
    public static void main(String[] args) {

        Test test = new Test();
        if (test instanceof Demo){
            System.out.println("y");
        }else {
            System.out.println("s");
        }
        // = s    不是一个类型的
    }
}

内存分析

  1. 堆 主要放对象
  2. 栈 局部变量,以及基本数据类型的变量
  3. 代码区:类和方法
  4. 数据区:常量池和静态变量

参数传递

public class Test {

    String string;
    
    public Test(String string) {
        this.string = string;
    }
    private static void chaes(Test test1) {
        test1.string="1011";
    }
}

public  class Demo {

    public static void chae(Test test){
        test = new Test("456");
    }

    public static void main(String[] args) {
        Test test = new Test("123");
        chae(test);
        System.out.println(test.toString());		// = 123

        Test test1 = new Test("789");
        chaes(test1);
        System.out.println(test1.string);			// = 1011
		System.out.println(test1.toString());		// = 1011
    }
    
}

异常

要捕多个异常要从小到大

快捷键生成异常 选中代码 Ctrl + Alt + T

Throwable

最大得到异常要写在最后面

Error

VirtualMachineError
AWTError

Exception

IOException
RuntimeException

常用关键字:

try //尝试着去处理可能会出现异常的东西

catch //捕获异常

finally //无论有没有异常都会去运行

throw //抛出异常

throws //方法抛出异常

public static void main(String[] args) {
    int a =1;
    int b = 0;

    try {
        System.out.println(a/b);
    }catch (ArithmeticException e){
        e.printStackTrace();				//打印错误信息
        System.out.println("程序出现异常");
    }finally {
        System.out.println("无论有没有异常都执行");
    }

}

主动抛出异常

public class Demo {

    public static void main(String[] args) {
        try {
            new Demo().test(1,0);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }	
        System.out.println("ass");				//异常后程序还会执行
    }

    private void test(int a,int b) throws ArithmeticException{
        if (b==0){            //throw主动抛出异常
            throw new ArithmeticException();
        }
        System.out.println(a/b);
    }
}

自定义异常

----MyException  新建自定义异常类继承想自定义的异常
public class MyException extends Exception{

    private int detail;

    public MyException(int a){			//新建异常值将错误的值打出来
        this.detail = a;
    }

    @Override
    public String toString() {			//创建toString方法
        return "MyException{" +
                "detail=" + detail +
                '}';
    }
}

public class Demo {
    static void demo(int a)throws MyException{
        System.out.println("传递的参数为:"+a);	
        if (a>10){
            throw new MyException(a);			//大于10就会抛出
        }
        System.out.println("OK");
    }

    public static void main(String[] args) {
        try {	
            demo(11);					//11大于10 所以抛出异常
        } catch (MyException e) {
            System.out.println(e);		//打印自定义异常  异常走捕获的内容
        }
    }
}

Math数学类

System.out.println(Math.abs(-12));      // = 12  绝对值属性
System.out.println(Math.pow(3,3));		// = 27  3的3次幂
System.out.println(Math.round(4.5));	// = 5   四舍五入
System.out.println(Math.sqrt(81));		// = 9   平方根
System.out.println(Math.max(12,32));	// = 32  最大值
System.out.println(Math.min(12,32));	// = 12  最小值

时间

Date date = new Date();
System.out.println(date);			//获取当前时间
---------老方法
System.out.println(date.getYear()+1900);    //从1900年开始
System.out.println(date.getMonth()+1);      //月份从0开始
System.out.println(date.getDate());         //日
System.out.println(date.getHours());        //小时
System.out.println(date.getMinutes());      //分
System.out.println(date.getSeconds());      //秒
----------新方法
Calendar calendar = Calendar.getInstance();

calendar.set(Calendar.DATE,calendar.get(Calendar.DATE)-1);		//可以通过这个方法减去多少天  

System.out.println(calendar.get(Calendar.YEAR));		//获取当前年份
System.out.println(calendar.get(Calendar.MONTH)+1);		//获取当前月份月份从0就开始
System.out.println(calendar.get(Calendar.DATE));		//获取当前日期

-----------Data时间转成Calendar
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);									//将data时间给calendar
System.out.println(calendar.get(Calendar.YEAR));		//获取当前年份
System.out.println(calendar.get(Calendar.MONTH)+1);		//获取当前月份月份从0就开始
System.out.println(calendar.get(Calendar.DATE));		//获取当前日期

格式化时间

Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = simpleDateFormat.format(date);
System.out.println(s);
----------------------字符串转成时间--------------------
String s = "2021-4-29 13:12:21";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
    Date date = simpleDateFormat.parse(s);
    System.out.println(date);
} catch (ParseException e) {
    e.printStackTrace();
}

计算时间

String s1 = "2021-4-29 13:12:21";       //开始时间
String s2 = "2021-4-29 17:18:21";       //结束时间

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = simpleDateFormat.parse(s1);
Date d2 = simpleDateFormat.parse(s2);

long long1 = d1.getTime();
long long2 = d2.getTime();

long sum = Math.abs(long1-long2);  //计算成毫秒级别的误差求绝对值

long miao = sum/1000;       //秒级别差

long fen = miao/60;         //分级别

long x1 = fen/60;
long x2 = fen%60;

System.out.println(x1+"小时"+x2+"分钟");

字符串

charAt(0) //拿到第0个字符

concat(“a”); //字符串后后面加a 拼接字符串

contains(“a”); //字符串中是否包含a

startsWith(“guan”); //字符串是否以guan 开始

endsWith(“xin”); //字符串是否以xin结尾

equalsIgnoreCase //忽略大小写是否一致

equals //判断两个字符串是否一致

indexOf(“c”) //判断字符串所在的位置

length() //字符串的长度

replace //替换

split //切割

substring(2,4) //截取

charAtString s = "guan";
System.out.println(s.charAt(0));    // = g   			拿到第0个字符

String s1 = s.concat("xin");		// s1= guanxin 		拼接字符串
String s = "guan";
System.out.println(s.contains("a"));   // = true   		里面是否包含了a 

String s = "guanxin";
System.out.println(s.startsWith("guan"));   //字符串是否以guan开始
System.out.println(s.endsWith("xin"));      //字符串是否以xin结尾

String s = "abc";
String s1 = "ABC";
System.out.println(s.equalsIgnoreCase(s1));	// =true 忽略大小写内容是否一致
System.out.println(s.equals(s1));			//判断两个字符是否一致
System.out.println(s.indexOf("c"));			// = 2   判断所在位置
System.out.println(s.length());				// = 3   字符串的chan'd
System.out.println(s.replace("c","a"));		// = aba  将c替换成a

String s = "哈哈_呵呵_吼吼";
String[] s1 = s.split("_");
System.out.println(s1[1]);					//= 呵呵    第1个数组

String s = "今天天气不错";					
System.out.println(s.substring(2,4));		// = 天气

StringBuffer 和 StringBuilder

StringBuffer和StringBuilder用法都是一样的

StringBuilder >StringBuffer // StringBuilder 速度更快

append //末尾添加字符串

insert //在第几位后加入的字符串

String s = stringBuilder.toString(); //转成字符串

StringBuilder stringBuilder = new StringBuilder("123");
System.out.println(stringBuilder);        // = 123
stringBuilder.append("456");
System.out.println(stringBuilder);        // = 123456
stringBuilder.insert(3,"789");
System.out.println(stringBuilder);        //123789456

字符串加法运算

String s = "12+12+31+32+52";
s = s.replace(" ","");      //去掉多余空格
String[] ss = s.split("\\+");

int sum = 0;
for (int i=0;i<ss.length;i++){
    int a = Integer.parseInt(ss[i]);
    sum += a;
}
System.out.println(sum);

侧手速

System.out.println("游戏马上开始");
Scanner scanner = new Scanner(System.in);
scanner.nextLine();

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND,calendar.get(Calendar.SECOND)+5);     //往后延迟5秒
Date date = calendar.getTime();
long end = date.getTime();          //结束时间

int con = 0;
while (end - new Date().getTime() >= 0){
    scanner.nextLine();
    con++;
}
System.out.println("您一共按了"+con+"次");

double pin = con/5;			// 5秒
DecimalFormat decimalFormat = new DecimalFormat(".00");
System.out.println("您的手速是:"+decimalFormat.format(pin)+"次/秒");

容器List,Map,Set.

  1. List 线性结构
  2. Set集合,非线性去除重复
  3. Map 映射 存储的时候以key:value的形式存储数据

List

用法一样 底层内存层面上有区别正常用感觉不到

ArrayList //查询效率比较高

LinkedList //删除和增加元素效率高

常用操作

add //添加

remove //删除

size //长度

get() //获取某个元素

contains //里面是否有这个数据

List<String> strings = Arrays.asList("1","2","3");		//新用法
strings.forEach(System.out::println);
Object obj = list.get(0);			//list是一个object类型
String s = (String) obj;			//强转成字符串
System.out.println(list.contains("1"));		//查找list有没有 1

Set

  • 不能有重复数据
  • 不是按照存储的数据进行存放的

HashSet //无序的

TreeSet //默认进行排序 升序

操作

add(); //添加元素

remove(); //删除元素 remove(“wode”); //直接写删除的内容

contains //里面是否有这个数据

Set set = new HashSet();
set.add("123");
set.add("456");
set.add("789");

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

Map容器

如果出现重复的key之前的会被顶掉

HashMap //不排序

TreeMap //根据key来排序的只能排int类型 map.put(11,“wang”); map.put(12,“wen”);

操作

put(key,value) //存数据

remove(key) //删数据

size() //长度

keySet //打印所有key

get //通过key 查询value值

Map map = new HashMap();
map.put("1","s");
map.put("3","sff");
map.put("2","sd");

map.remove("1");		//删除 key 1 
System.out.println(map);	 			// = {2=sd, 3=sff}
System.out.println(map.keySet());		// = [2, 3]		打印所有的key
System.out.println(map.get("2"));		//查询对应的value

迭代器

next //下一个

hasNext //是否还有下一个

List

List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");

Iterator iterator = list.iterator();		//创建迭代器

while (iterator.hasNext()){					//判断是否有下一个
    String s = (String) iterator.next();	
    System.out.println(s);
}

Set

Set set = new HashSet();
set.add("123");
set.add("456");
set.add("789");

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

Map

方案1
Map map = new HashMap();
map.put("xxx","123");
map.put("sss","456");
map.put("aaa","789");

Set set = map.keySet(); //拿到所有的key
Iterator iterator = set.iterator();
while (iterator.hasNext()){
    String s = (String) iterator.next();
    System.out.println(s);
    System.out.println(map.get(s));     //通过key拿到所有value
}
方案2
Map map = new HashMap();
map.put("xxx","123");
map.put("sss","456");
map.put("aaa","789");


Set set = map.entrySet();       //set里面装的是entry
Iterator iterator = set.iterator();
while (iterator.hasNext()){
    Map.Entry entry = (Map.Entry) iterator.next();
    System.out.print(entry.getKey());
    System.out.println("   "+entry.getValue());
}

泛型

Map<String,String> map = new HashMap<>();
map.put("1","123");
map.put("2","456");
map.put("3","789");

String s = map.get("1");
System.out.println(s);			//= 123

Flie类

多线程

基础

Thread

线程开启不一定立即执行,由cpu调度

  1. 子类继承Thread
  2. 重写run()方法
  3. 写入线程体
  4. 去主线程调创建线程对象,调用start()方法启动线程
  5. 启动:子类对象.start();
public class Test extends Thread{

    @Override
    public void run() {
        //run方法线程体
        System.out.println("子线程方法");
    }

    public static void main(String[] args) {
        //main方法  主线程
        Test test = new Test();
        test.start();       //使用start方法调用主线程和子线程同时运行   
    }
}

Runnable

实现接口Runnable具有多线程能力

启动线程:传入目标对象+Thread对象.start();

public class Test implements Runnable {

    @Override
    public void run() {
        System.out.println("子线程方法");
        //	System.out.println(""+Thread.currentThread().getName());            //线程的名字  通过getname获取
    }

    public static void main(String[] args) {
        Test test = new Test();
        new Thread(test).start();		
        //   new Thread(test,"我").start();           //可以给线程起名字
    }
}
new Thread(new Runnable() {
    @Override
    public void run() {

    }
}).start();

Callable

callable和Runnable的区别是callable可以有返回值

线程停止

public class Test implements Runnable{

    private boolean loop = true;

    @Override
    public void run() {
        int i = 0;
        while (loop){
            i ++;
            System.out.println("run···"+i);
        }
    }

    public void stop(){
        this.loop = false;
    }

    public static void main(String[] args) {
        Test test = new Test();
        new Thread(test).start();
        try {
            Thread.sleep(1000);
            test.stop();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

时间倒计时

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

    Date date = new Date(System.currentTimeMillis());

    while (true){
        System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
        date = new Date(System.currentTimeMillis());
        Thread.sleep(1000);
    }
}

礼让

Thread.yield();     //礼让

插队

public class Test 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 {

        Test test = new Test();
        Thread thread = new Thread(test);
        

        //
        for (int i = 0; i < 300; i++) {
            if (i==200){
                thread.start();				//启动线程
                thread.join();				//强制线程执行完再执行主线程
            }
            System.out.println("main"+i);
        }
    }
}

查看线程状态

线程只能启动一次

NEW //尚未启动的线程处于此状态

RUNNABLE //执行的线程

BLOCKED //阻塞等待监视器锁定的线程处于此状态

WAITING //正在等待另一个线程执行特定动作的线程处于此状态

TIMED WAITING //正在等待另一个线程执行动作达到的线程处于此状态

TERMINATED //已退出的线程

Thread.State state = thread.getState();
System.out.println(state);      // = New		创建线程未启动
thread.start();     			//启动线程
state = thread.getState();		//获取线程状态
System.out.println(state);      // = RUNNABLE	线程启动
state = thread.getState();		//获取线程状态
System.out.println(state);      // = TIMED_WAITING 线程正在运行

线程的优先级

线程优先级数字越大越高

setPriority

主线程默认 5

public class Test{

    public static void main(String[] args) {

        MyPriority myPriority = new MyPriority();
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);
        Thread t6 = new Thread(myPriority);
        t1.start();
        
        t2.setPriority(1);
        t2.start();

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

        t4.setPriority(Thread.MAX_PRIORITY);	//最大 = 10
        t4.start();

        t5.setPriority(9);
        t5.start();

        t6.setPriority(1);
        t6.start();

    }

}

class MyPriority implements Runnable{
    @Override
    public void run() {
        //getPriority  线程的优先级
        System.out.println(Thread.currentThread().getName()+"---->"+Thread.currentThread().getPriority());
    }
}

Lamda表达式

interface Ilove{					//实现接口
    void love(int a);
}

class Love implements Ilove {		//实现他的类

    @Override
    public void love(int a) {
        System.out.println("I love you  "+a);
    }
}

public class Test {					
    public static void main(String[] args) {
        Ilove ilove = new Love();
        ilove.love(2);
    }
}
简化方法1静态内部类
interface Ilove{
    void love(int a);
}

public class Test {

    static class Love implements Ilove {			//静态内部类

        @Override
        public void love(int a) {
            System.out.println("I love you  "+a);
        }
    }

    public static void main(String[] args) {
        Ilove ilove = new Love();
        ilove.love(2);
    }
}
简化方法2局部内部类
interface Ilove{
    void love(int a);
}

public class Test {


    public static void main(String[] args) {

        class Love implements Ilove {			//将类名放到局部里

            @Override
            public void love(int a) {
                System.out.println("I love you  "+a);
            }
        }
        
        Ilove ilove = new Love();
        ilove.love(2);
    }
}

实现方法3匿名内部类
interface Ilove{
    void love(int a);
}

public class Test {

    public static void main(String[] args) {

        Ilove ilove = new Ilove() {				//直接使用接口
            @Override
            public void love(int a) {
                System.out.println("I love you  "+a);
            }
        };
        ilove.love(2);
    }
}
实现方法4 Lambda简化
interface Ilove{
    void love(int a);
}

public class Test {

    public static void main(String[] args) {
        Ilove ilove = (int a) ->{
            System.out.println("I love you  "+a);
        };
        ilove.love(520);
    }
}

多线程进阶

进程:一个程序可以包含多个线程,只要包含一个

线程就是一个单独的资源类,没有任何附属操作 1.属性2.方法

java默认有2个线程,1、main线程 2、GC线程主要做垃圾回收

System.out.println(Runtime.getRuntime().availableProcessors());		//获取cpu的核数

线程的状态

public enum State {
    //线程新生
    NEW,
    //运行
    RUNNABLE,
    //阻塞
    BLOCKED,
    //等待
    WAITING,
    //超时等待
    TIMED_WAITING,
    //终止
    TERMINATED;
}

Synchronized锁

class Ticket {
    private int number = 50;
    //synchronized  锁	加上synchronized变得有秩序
    public synchronized void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余:"+number);
        }
    }
}

    public static void main(String[] args) {
        //多线程操作
        Ticket ticket = new Ticket();	
        
   		//使用Lamda表达式  (参数)->{ 代码 } 方法启动线程
        new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"A").start();

        new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"B").start();

        new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"C").start();
        
    }

Lock锁

Lock 接口

synchronized 和 Lock区别

  • synchronized 内置java关键字,Lock是一个java类
  • synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
  • synchronized 会自动释放锁, Lock必须要手动释放锁,如果不释放锁,会被死锁
  • synchronized 当线程1阻塞了,线程2会进行等待
  • Lock 当线程1阻塞了,线程2不一定等待
  • synchronized 可重入锁,不可以中断 非公平 ;Lock 可重入锁 不可以中断 可以判断锁 非公平(可以自己设置)
  • synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码

Lock l = …; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }

ReentrantLock //可重入锁 (常用)

ReentrantReadWriteLock.ReadLock //读锁

ReentrantReadWriteLock.WriteLock //写锁

lock三部

new ReentrantLock();
lock.lock();    	//加锁
lock.unlock();      //解锁

使用lock锁卖票

class Ticket {

    private int number = 50;
    
    Lock lock = new ReentrantLock(false);
    public void sale(){

        lock.lock();    //加锁

        try {

            if (number>0){
                System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余:"+number);
            }

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

    public static void main(String[] args) {
        //多线程操作
        Ticket ticket = new Ticket();

        new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"A").start();

        new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"B").start();

        new Thread(()->{ for (int i=1;i<40;i++){ ticket.sale(); } },"C").start();


    }

线程等待 wait() 生产者消费者问题

初始方法

class Data {
    private int number = 0;
    //+1
    public synchronized void increment() throws InterruptedException {
        while (number != 0){   //当不等于0的时候等待 -1 线程操作		//防止虚假唤醒用while   否则用if
            this.wait();;   //等待
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();   //通知线程+1完成
    }
    //-1
    public synchronized void decrement() throws InterruptedException {
        while (number == 0){   //当等于0的时候等待 +1 线程操作			//防止虚假唤醒用while   否则用if
            this.wait();    //如果=0就等待
        }
        number --;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        this.notifyAll();   //通知线程 -1 完成
    }
}

    public static void main(String[] args) {
        Data data = new Data();

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

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

Lock锁

condition.await();

condition.signalAll();

class Data {

    private int number = 0;

    Lock lock = new ReentrantLock();

    Condition condition = lock.newCondition();

    public void increment() throws InterruptedException{
        lock.lock();
        try {
            while (number != 0){
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            condition.signalAll();      //通知其他线程 +1 完毕
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();      //释放锁
        }
    }

    // -1
    public void decrement() throws InterruptedException{
        lock.lock();
        try {
            while (number==0){
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            condition.signalAll();  //通知其他线程 -1 完毕
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();      //释放锁
        }
    }
}

    public static void main(String[] args) {
        Data data = new Data();

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

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

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

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

    }

精准执行

按照顺序依次执行

class Data {

    Lock lock = new ReentrantLock();

    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();

    private int number = 1;

    public void printA(){
        lock.lock();                    //打开锁
        try {
            while (number != 1){
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAA");
            number = 2;
            condition2.signal();        //只唤醒 condition2
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();              //关闭锁
        }
    }

    public void printB(){
        lock.lock();                    //打开锁
        try {
            while (number != 2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAA");
            number = 3;
            condition3.signal();        //只唤醒 condition3
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();              //关闭锁
        }

    }

    public void printC(){
        lock.lock();                    //打开锁
        try {
            while (number != 3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAA");
            number = 1;
            condition1.signal();        //只唤醒 condition1
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();              //关闭锁
        }

    }

}

    public static void main(String[] args) {
        Data data = new Data();

        new Thread(()->{
            for (int i=0;i<10;i++){data.printA();}
        },"A").start();
        new Thread(()->{
            for (int i=0;i<10;i++){data.printB();}
        },"B").start();
        new Thread(()->{
            for (int i=0;i<10;i++){data.printC();}
        },"C").start();

    }

8锁

8锁,就是关于锁的8个问题

1、标准情况下,两个线程先打印 发短信还是 先打印 打电话? 1/发短信 2/打电话

1、sendSms延迟4秒,两个线程先打印 发短信还是 打电话? 1/发短信 2/打电话

synchronized 锁的对象是方法的调用者

    public static void main(String[] args) {
        Phone phone = new Phone();
        // 锁的存在
        new Thread(()->{ phone.sendSms(); },"A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{ phone.call(); },"B").start();
    }

class Phone{
    // synchronized 锁的对象是方法的调用者!、
    // 两个方法用的是同一个对象调用(同一个锁),谁先拿到锁谁执行!
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);// 抱着锁睡眠
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}
// = 4秒后执行  发短信,后执行打电话

普通方法没有锁!不是同步方法,就不受锁的影响,正常执行

增加了一个普通方法后!先执行发短信还是Hello?// 普通方法

两个对象,两个同步方法, 发短信还是 打电话? // 打电话

public class Test04 {
    public static void main(String[] args) {
        // 两个对象,两个调用者,两把锁!
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();
        //锁的存在
        new Thread(()->{ phone1.sendSms(); },"A").start();

        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{ phone2.call(); },"B").start();

        new Thread(()->{ phone2.hello(); },"C").start();
    }
}
class Phone2{

    public synchronized void sendSms(){ // synchronized 锁的对象是方法的调用者!
        try {
            TimeUnit.SECONDS.sleep(4);      //延迟4秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }

    public void hello(){                //  这里没有锁!不是同步方法,不受锁的影响
        System.out.println("hello");
    }
}
//  = 先执行打电话,接着执行hello,4秒执行发短信

static静态的同步方法,锁的是Class

增加两个静态的同步方法,只有一个对象,先打印 发短信?打电话?

两个对象!增加两个静态的同步方法, 先打印 发短信?打电话?

public class Test04 {
    public static void main(String[] args) throws InterruptedException {
        // 两个对象的Class类模板只有一个,static,锁的是Class
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();
        //锁的存在
        new Thread(()->{ phone1.sendSms(); },"A").start();
        
        // 捕获
        TimeUnit.SECONDS.sleep(1);
     
        new Thread(()->{ phone2.call(); },"B").start();
    }
}
// Phone3唯一的一个 Class 对象
class Phone3{
    // synchronized 锁的对象是方法的调用者!
    // static 静态方法
    // 类一加载就有了!锁的是Class
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public static synchronized void call(){
        System.out.println("打电话");
    }
}
// 先执行发短信,后执行打电话

1个静态的同步方法,1个普通的同步方法 ,一个对象,先打印 发短信?打电话?

1个静态的同步方法,1个普通的同步方法 ,两个对象,先打印 发短信?打电话?

public class Test04  {
    public static void main(String[] args) {
        // 两个对象的Class类模板只有一个,static,锁的是Class
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        //锁的存在
        new Thread(()->{ phone1.sendSms(); },"A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{ phone2.call(); },"B").start();
    }
}
// Phone3唯一的一个 Class 对象
class Phone4{
    // 静态的同步方法 锁的是 Class 类模板
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    // 普通的同步方法  锁的调用者(对象),二者锁的对象不同,所以不需要等待
    public synchronized void call(){
        System.out.println("打电话");
    }
}
// 7/8 两种情况下,都是先执行打电话,后执行发短信,因为二者锁的对象不同,
// 静态同步方法锁的是Class类模板,普通同步方法锁的是实例化的对象,
// 所以不用等待前者解锁后 后者才能执行,而是两者并行执行,因为发短信休眠4s
// 所以打电话先执行。

S-Callable

Callable接口类似于Runnable

不同于:

  1. 可以有返回值
  2. 可以抛出异常
  3. 方法不同 run(),call();
public class Test04 {

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

        MyThread myThread = new MyThread();
        FutureTask futureTask = new FutureTask(myThread);   //适配类
        new Thread(futureTask,"A").start();           		//启动线程    调用方法
        System.out.println(futureTask.get());               //获取返回值 = Callable
    }
}

class MyThread implements Callable<String>{

    @Override
    public String call() throws Exception {
        System.out.println("call");
        return "Callable";
    }
}

常用辅助类

CountDownLatch //加法计数

CyclicBarrier //减法计数

Semaphore //信号量

CountDownLatch

countDownLatch.countDown(); // 数量-1

countDownLatch.await(); // 等待计数器归零,然后再向下执行

每次有线程调用 countDown() 数量-1,假设计数器变为0,countDownLatch.await() 就会被唤醒,继续执行!

public class Test04 {

    public static void main(String[] args) throws InterruptedException {
        // 总数是6,必须要执行任务的时候,再使用!
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()
                        +" Go out");
                countDownLatch.countDown(); // 数量-1
            },String.valueOf(i)).start();
        }
        countDownLatch.await(); // 等待计数器归零,然后再向下执行
        System.out.println("Close Door");
    }
    
}
CyclicBarrier
public class Test04 {
    public static void main(String[] args) {
        /*
         * 集齐7颗龙珠召唤神龙
         */
        // 召唤龙珠的线程
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("召唤神龙成功!");
        });
        for (int i = 1; i <=7 ; i++) {
            final int temp = i;
            // lambda能操作到 i 吗
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()
                        +"收集"+temp+"个龙珠");
                try {
                    cyclicBarrier.await(); // 等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
Semaphore 信号量

semaphore.acquire(); //获得,假设如果已经满了,等待,等待被释放为止!

semaphore.release(); //释放,会将当前的信号量释放 + 1,然后唤醒等待的线程!

public class Test04 {
    
    public static void main(String[] args) {
        //线程数量:停车位
        Semaphore semaphore = new Semaphore(3);	//控制最大的线程
        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                try {
                    semaphore.acquire();		//获得车位
                    System.out.println(Thread.currentThread().getName()+"青岛车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();		//释放车位
                }
            },String.valueOf(i)).start();
        }
    }
}

读写锁 ReadWriteLock

public class Test04 {
    public static void main(String[] args) {
        
        //MyCache myCache = new MyCache();
        
        MyCacheLock myCacheLock = new MyCacheLock();
        
        for (int i = 1; i <= 5 ; i++) {        // 写入
            final int temp = i;
            new Thread(()->{
                myCacheLock.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        
        for (int i = 1; i <= 5 ; i++) {        // 读取
            final int temp = i;
            new Thread(()->{
                myCacheLock.get(temp+"");
            },String.valueOf(i)).start();
        }
    }
}

class MyCacheLock{      //加锁
    private volatile Map<String,Object> map = new HashMap<>();

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();    // 读写锁: 更加细粒度的控制
    
    // 存,写入的时候,只希望同时只有一个线程写
    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()+"写入OK");
        } 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()+"读取OK");
        } 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()+"写入OK");
    }
    // 取,读
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"读取"+key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取OK");
    }
}

!!!!!!阻塞队列

https://www.kuangstudy.com/bbs/1374937897278402561

https://www.kuangstudy.com/bbs/1374936485165297666

集合不安全

List

//并发下ArrayList 是不安全的		多线程下会报并发性异常 ConcurrentModificationException

    public static void main(String[] args) {
        // 并发下 ArrayList 不安全的吗,Synchronized;
        /*
         * 解决方案;
         * 方案1、List<String> list = new Vector<>();
         * 方案2、List<String> list =
         * Collections.synchronizedList(new ArrayList<>());
         * 方案3、List<String> list = new CopyOnWriteArrayList<>();
         */
       /* CopyOnWrite 写入时复制  COW  计算机程序设计领域的一种优化策略;
        * 多个线程调用的时候,list,读取的时候,固定的,写入(覆盖)
        * 在写入的时候避免覆盖,造成数据问题!
        * 读写分离
        * CopyOnWriteArrayList  比 Vector Nb 在哪里?
        */    
        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }

set

HashSet 的底层就是一个HashMap

Set set = new HashSet<>(); //不安全

Set set = Collections.synchronizedSet(new HashSet<>()); //安全

public static void main(String[] args) {
    Set<String> set = new CopyOnWriteArraySet<>();//安全
    for (int i = 1; i <=30 ; i++) {
        new Thread(()->{
            set.add(UUID.randomUUID().toString().substring(0,5));
            System.out.println(set);
        },String.valueOf(i)).start();
    }
}

Map

map 是这样用的吗? 不是,工作中不用 HashMap

默认等价于什么? new HashMap<>(16,0.75);

Map<String, String> map = new HashMap<>();

扩展:研究ConcurrentHashMap的原理

public static void main(String[] args) {

    Map<String,String> map = new ConcurrentHashMap<>();
    for (int i = 0; i < 30; i++) {
        new Thread(()->{
            map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));
            System.out.println(map);
        },String.valueOf(i)).start();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值