Java进阶

一、常用类

1) String相关类

1.String

1.1 初识字符串

声明字符串

//方法一 声明时直接赋值
String s = new String("uden");
//方法二 先声明后赋值
String s = new String();
s = sc.next();

转换为二进制的方法

//插一个函数 重要
result = Integer.toBinaryString(num)//将int 数字转换为二进制字符串(String)
1.2字符串的一系列操作

连接字符串

public class join{
public static void main(String[] args){
        String s1 = new String("Hello");
        String s1 = new String("Java");
        String s = s1+" "+s2;
        System.out.println(s);
  }
}

获取字符串长度

int size = str.length();

字符串查找

int index = str.indexOf(substr);//返回substr首次出现在str里的下标;
//例如
int index = str.indexOf("a");

int index = str.lastindexOf(substr);//返回substr最后一次出现在str里的下标;
//例如
int index = str.lastindexOf("a");

获取指定位置的字符

char mychar = str.charAt(int index);

获取子字符串

String substr = str.substring(int beginIndex);//获取从指定索引位置开始直到该字符串结尾的子串

String substr = str.substring(int beginIndex,int endIndex);//从begin到end的子串

去除空格

str.trim();

字符串替换

str.replace(char oldChar,char newChar);
str.replaceAll(String regex,String newstr);//注意这里需使用正则表达式

比较字符串
比较字符串不能用 “==” 因为字符串是对象,即使是内容相同,内存地址也是不同的,也会是false;
这里应该使用equals方法;

str.equals(String otherString);//返回Boolean类型

str.equalsIgnoreCase(String otherString);//忽视大小写的情况下比较字符串  返回Boolean类型

按字典顺序比较两个字符串

str.compareTo(String otherstr);//如果str在otherstr之前则返回一个负值,否则返回正值,如果相等则返回0;

大小写转换

public static void main(String[] args){
    String str = new String("abc DEF");
    String newstr1 = str.toUpperCase();//转换为大写
    String newstr2 = str.toLowerCase();//转换为小写
    System.out,println(newstr1);//注意,转换时,数字或非字符是不受影响的
    System.out,println(newstr1);
}

字符串分割

String[] firstArray = str.split("\\.",2);
//第一个参数为正则表达式,第二个分割次数,也可以不写

字符串反转

 StringBuilder stringBuilder = new StringBuilder(s);
 System.out.print(stringBuilder.reverse().toString());
1.3 关于正则表达式(初级)

注意: 在正则表达式中“.”代表任何一个字符,因此在正则表达式如果想使用普通意义的"." ,需要写成"\.";
正则表达式

2. StringBuffer

2.1初始化

StringBuffer() 构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符。

StringBuffer sb = new StringBuffer("william");
2.2 关于StringBuffer的一些方法

添加字符

//append方法  在末尾添加字符或者字符串
StringBuffer sb = new StringBuffer("william");
sb.append("wiam");//结果应是williamwiam,即添加到末尾
System.out.println(sb);

//insert方法  在指定位置添加字符
 sb.insert(0,"w");
 System.out.println(sb);//结果为wabcb

删除字符

//deleteCharAt()方法  删除指定位置的字符
sb.deleteCharAt(1); 
System.out.println(sb);//结果wbcb

//delete方法  删除指定位置的字符
sb.delete(1,3);
System.out.println(sb);//结果wb  即不包括位置的最后一位

替换指定位置的字符串


//Buffer里的replace方法
sb.replace(0,1,"chengningzuishuai");
System.out.println(sb);//结果chengningzuishuaib 最后一个依然为开区间

反转字符串

//reverse方法
sb.reverse();
System.out.println(sb);//结果biauhsiuzgningnehc

参考:https://blog.csdn.net/weixin_44519467/article/details/103947361?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163092725916780265450059%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163092725916780265450059&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-2-103947361.first_rank_v2_pc_rank_v29&utm_term=stringbuffer&spm=1018.2226.3001.4187

3. StringBuilder

3.1 初始化
StringBuilder  sb = new StringBuilder("Hello mercury");
3.2 几个常用的方法

和StringBuffer的都一样
添加字符串

//append方法
sb.append("chenningzuishuai");
System.out.println(sb);//结果Hello mercurychenningzuishuai

//insert
sb.insert(2,"william");
System.out.println(sb);//结果为Hewilliamllo mercurychenningzuishuai

删除字符串

//deleteCharAt()方法  删除指定位置的字符
sb.deleteCharAt(1); 
System.out.println(sb);//结果Hwilliamllo mercurychenningzuishuai

//delete方法  删除指定位置的字符
sb.delete(1,30);
System.out.println(sb);//结果Hshuai  即不包括位置的最后一位

替换指定位置的字符串


//Builder里的replace方法
sb.replace(0,1,"chengningzuishuai");
System.out.println(sb);```

反转字符串

//reverse方法
sb.reverse();
System.out.println(sb);

4. 关于这几个字符串的区别

StringStringBufferStringBuilder
String的值是不可变的(里面是final),这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量可变类,速度更快
不可变可变可变
线程安全线程不安全
多线程操作字符串单线程操作字符串

(1)如果要操作少量的数据用 String;

(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;

(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。

在不考虑线程安全的情况下,现阶段应使用StringBuilder而不是StringBuffer

参考:https://blog.csdn.net/itchuxuezhe_yang/article/details/89966303?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163092981516780366546179%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163092981516780366546179&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-89966303.first_rank_v2_pc_rank_v29&utm_term=stringbuilder&spm=1018.2226.3001.4187

2) Math类

定义了一些常量,如 Math.PI Math.E

1.常用的数学方法

  1. 三角函数方法
public class mathdemo {
    public static void main(String[] args) {
        System.out.println("90度的正弦值:"+Math.sin(Math.PI/2));//注意这几个函数参数和返回值都是double
        System.out.println("0度的余弦值:"+Math.cos(0));
        System.out.println("60度的正弦值:"+Math.tan(Math.PI/3));
    }
}
  1. 指数函数方法
public class ExponentFunction {
    public static void main(String[] args) {//这几个函数依旧是double参数和double返回值
        System.out.println("e的平方值" + Math.exp(2));//e的二次方
        System.out.println("以e为底2的对数值" + Math.log(2));
        System.out.println("以10为底2的对数值" + Math.log10(2));//这个10不可以变哈
        System.out.println("4的平方根值" + Math.sqrt(4));
        System.out.println("8的立方根值" + Math.cbrt(8));
        System.out.println("2的2次方值" + Math.pow(2,2));
    }
}

  1. 取整函数
//Math类里的取整函数
public static double ceil( double a);//向上取整
public static double floor( double a);//向下取整
public static double rint( double a);//返回和参数最接近的整数,如果同样接近,则结果取整数
  1. 取最大值,最小值,绝对值函数方法
public static void main(String[] args){
   System.out.println("4和8较大者"+Math.max(4,8));
   System.out.println("4.4和4较小者"+Math.min(4.4,4));
   System.out.println("-7的绝对值"+Math.abs(-7));
}

3) Random类

public class randomdemo {
    public static void main(String[] args) {
        Random r = new Random();//实例化一个random
        //随机产生一个整数s
        System.out.println("随机产生一个整数"+r.nextInt());
        //随机产生一个大于等于0且小于10的整数
        System.out.println("随机产生一个大于等于0且小于10的整数"+r.nextInt(10));
        System.out.println("随机产生布尔型的值"+r.nextBoolean());
        System.out.println("随机产生一个双精度型的的值"+r.nextDouble());
        System.out.println("随机产生一个浮点型的的值"+r.nextFloat());

    }

}

4) 大数字计算类

1. BigInteger

public class BigIntegerdemo {
    public static void main(String[] args) {
        BigInteger big = new BigInteger("4");//实例化一个大数据
        //取该数据加2的操作
        System.out.println("加法操作"+ big.add(new BigInteger("2")));
        System.out.println("减法操作"+ big.subtract(new BigInteger("2")));
        System.out.println("乘法操作"+ big.multiply(new BigInteger("2")));
        System.out.println("除法操作"+ big.divide(new BigInteger("2")));
        System.out.println("乘方操作"+ big.pow(2));
        System.out.println("取相反数操作"+ big.negate());
    }

}

2. BigDecimal

与BigInteger不同的是,BigDecimal可以进行小数的计算,包括float和double,值得注意的是,这个的加法减法等方法需要自己去定义

//有两种构造方法
public BigDecimal(double val);//将double变为大数类型
public BigDecimal(String val);//将字符串变为大数类型
public class BigDecimalDemo {

        public static void main(String[] args){
            BigDecimalDemo  big = new BigDecimalDemo();
            System.out.println("两数相加的结果"+big.add(7.5,8.9));
        }


        public BigDecimal add(double value1, double value2){//加法
            BigDecimal b1 = new BigDecimal(Double.toString(value1));//这里直接填value1也可以
            BigDecimal b2 = new BigDecimal(Double.toString(value2));
            return b1.add(b2);
        }
    }

二、集合

集合的索引也是从0开始

1)Collection接口

Collection是根接口,一般不直接使用,后面的list接口和Set接口都继承了Collection接口,因此是通用的;而遍历集合一般都是通过迭代器实现;这里给出一个实例

import java.util*
public class Muster{
    public static void main(){
       Collection<String> list = new ArrayList<>();
       list.add("a");
       Iterator<String> it = list.iterator();//迭代器是集合的一种方法
       while(it.hasNext()){//这个判断一定要记得,不然会抛异常
          String str = it.next();
          System.out.println(str);
       }
    }
}

除此之外,collection中主要有以下方法

方法功能描述
add(E e)添加指定对象
remove(Object o)将指定对象移除
isEmpty判断是否为空
itertor()迭代器
size()获取元素个数

2)List集合

List中主要包含了两种实现类,即ArrayList和LinkedList,他们的主要区别就是,List中类似数组存储,而LinkedList则是使用链表存储。

//实例化
List<E>  list = new ArrayList<>();
List<E>  list2 = new LinkedList<>();

List集合继承了collection接口,有他的所有方法,并且多了两个方法:

方法作用
get(int index)获取指定那个位置的集合元素
set(int index,Object obj)顾名思义就是设置元素的

来个例子:

public class ArrayListdemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.remove(2);//移除指定位置的集合元素
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

3)Set集合

Set继承了Collection接口;Set集合对象不按特定的顺序排序,只是简单的加入数据,但是Set集合中不能包含重复的对象,常用的实现类有HashSet类和TreeSet类

1. HashSet实现类

数据结构:JDK1.8之前:哈希表(数组+单向链表);JDK1.8之后:哈希表(数组+单向链表+红黑树),当链表长度超过阈值(8)时,链表将转换为红黑树。

特点:查询快,元素无序,元素不可重复,没有索引;

底层分析:哈希表底层用数组+单向链表实现,即使用链表处理冲突,同一Hash值的元素都存储在一个链表里,但是当位于一个链表中的元素较多,即Hash值相等的元素较多,通过key值依次查找的效率降低。JDK1.8之后,哈希表底层采用数据+单向链表+红黑树实现,当链表长度超过阈值(8)时,链表将转换为红黑树,极大缩短查询时间。

2. TreeSet实现类

数据结构:红黑树

特点:查询快,元素有序,元素不可重复,没有索引;

底层分析:TreeSet实现了继承于Set接口的SortedSet接口 ,它支持两种排序方法,自然排序和定制排序,自然排序的意思就是放入元素“a”,“b”,a会自然地排在b前面,其中还有几个特有方法。

first() 返回第一个元素; last() 返回最后一个元素;comparator() 返回排序比较器;

引用自https://blog.csdn.net/weixin_42559574/article/details/108203595?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163110337616780255269862%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163110337616780255269862&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-108203595.first_rank_v2_pc_rank_v29&utm_term=Java%E9%9B%86%E5%90%88%E7%B1%BB&spm=1018.2226.3001.4187

3)Map集合

Map没有继承collection类,它提供的是key到value的映射,Map中不能包含相同的key,每个key只能映射一个value;其实key就相当于下标。

1. Map接口

其包含的主要方法

方法功能
put(K key,V value)添加指定的key到value的映射关系
containKey(Object key)如果包含指定key的映射关系,则返回true
containsValue(Object value)如果包含指定key的映射关系,则返回true
get(Object key)如果存在指定的key对象,则返回对应的value值,否则返回null
keySet()返回所有的key的值形成的Set集合
values()返回所有的value的值形成的Collection集合

2. Map接口实现的类

主要有HashMap和TreeMap,建议使用HashMap,因为效率更高,而TreeMap有一定的顺序,若希望Map集合里的对象也有一定的顺序,则使用TreeMap实现Map集合

//实例化
//HashMap
Map<String,String> map = new HashMap<>();
Map<String,String> map = new TreeMap<>();

三、 枚举类型

1)枚举类的使用

  1. 枚举类的理解:类的对象只有有限个,确定的,就为枚举类
  2. 当需要定义一组常量时,强烈建议使用枚举类
  3. 如果枚举类中只有一个对象,则可以作为单例模式的实现方式

2)使用enum类型来定义常量

 public enum con{
        con_A,
        con_B,
        con_C
    }

3)枚举类的常用方法

方法名称作用使用方法
values()将枚举类型的成员以数组的形式返回(也可以通过该方法获取枚举类类型的成员)枚举类型名称.values()
valuesOf()将普通字符串转换为枚举实例枚举类型名称.valueOf(“abc”)
compareTo()比较两个枚举对象在定义时的顺序(正值表示在参数在调用该方法的枚举对象之前,负值则是之后)枚举对象.compareTo()
ordinal得到枚举成员的位置索引枚举对象.ordinal()

构造函数在写枚举类构造方法的时候权限修饰符应该为private;

四、泛型

1)初识泛型

把元素的类型设计成一个参数,这个参数就是泛型

如果集合不使用泛型
在这里插入图片描述
就会出现种种问题

使用泛型
在这里插入图片描述
问题迎刃而解

然后输出(这里复习一下增强for循环和迭代器)
在这里插入图片描述

注意点:集合中<>中填泛型时不能时基本数据类型(比如int),必须是一个类,例如是int需要填包装类Integer

2)自定义泛型

1、泛型类

这里的T相当于一个参数,就当成其他的数据类型一样用
在这里插入图片描述
在这里插入图片描述

public class test{
    @Test
    public void test1(){
     //如果定义了泛型类,实例化没有指明类的泛型,则认为泛型类型为Object类型
     //要求:如果大家定义了类是带泛型的建议在实例化要指明类的泛型
     Order order = new Order();
     order.setOrderT(123);
     order.setOrderT("ABC");
     //建议:实例化时指明类的泛型
     Order<String> order1 = new Order<String>("orderAA")//这里有一个构造方法传参,String就是传入类的泛型参数
    }

}
  • 如果子类在继承带泛型的父类的时候,指明了泛型的类型,则在实例化子类的对象时,不再需要指明泛型

  • 静态方法中不能使用泛型

  • 异常类不能是泛型类

3)泛型方法

泛型方法里的泛型参数和泛型类里的泛型参数是没有关系的
在这里插入图片描述
上图中因为返回的时List类型的所以还有个List,特别注意标明是泛型方法要有个 < E >在这里插入图片描述
测试泛型方法
在这里插入图片描述
泛型方法是可以声明为静态的.原因就是:泛型参数实在调用方法时确定的,并非是在实例化类时确定的

4)通配符的使用

通配符 : ?
在这里插入图片描述

public void print(List<?> list){
   Iterator<?> iterator = list.iterator();
   while(iterator.hasNext()){
    Object obj = iterator.next;//这里当然不能用 ? obj 声明啦
    System.out.println(obj);
   }
}

有限制条件的通配符的使用

  • ? extends Person 向下限制,只接受Person类以下的类型

  • ? super Person 向下限制,只接受Person类以上的类型

//实例
public void doSomething(A<? extends List> a){
}
//实例
List<? extends list> list = null;

在这里插入图片描述
比如在这里 list1 = list5 就会报错

五、注解

1)初识注解

在这里插入图片描述
在这里插入图片描述

2)元注解

元注解主要是在定义自定义的注解的时候用
在这里插入图片描述

3)自定义注解

在这里插入图片描述

在这里插入图片描述

//自定义注解
public class Test03{
   //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
   @MyAnnotation2(age = 18,name = "陈帅");
   public void test(){}
   @Target({Element.TYPE,Elementtype.NETHOD})
   @Retention(RetenionPolicy.RUNTIME)
   @interface MyAnnotation2{
   //注解的参数: 参数类型 + 参数名();
   String name() default "";//这里设置默认值为空,这样就不用传参了
   int age();
   int id() default -1 ;//设置默认值为-1
   String[] schools default("西柚牛逼","Mercury最帅");    
   }
  @Target({Element.TYPE,Elementtype.NETHOD})
  @Retention(RetenionPolicy.RUNTIME)
  @interface MyAnnotation3{
  String value();
  }
} 

如果有default即有默认值,可以不用赋值

六、反射

1)关于静态语言和动态语言

在这里插入图片描述

2)初识反射

在这里插入图片描述

在这里插入图片描述
例如

//什么反射
public class Test02{
  public static void main(String[] args) throws ClassNotFoundException {
     //通过反射获取类的Test的对象
     Class c1 = class.forName("com.kuang.reflection.User");//User在这个位置
     System.out.println(c1);

     Class c2 = class.forName("com.kuang.reflection.User");
     Class c3 = class.forName("com.kuang.reflection.User");
     Class c4 = class.forName("com.kuang.reflection.User");
     
     //一个类在内存中只有一个class类
     //一个类被加载后,类的整个结构都会被封装在class对象中
      System.out.println(c2.hashcode()); 
      System.out.println(c3.hashcode()); 
      System.out.println(c4.hashcode());
  }
}

class User{...}//在这里就不详细列出来了

3)获取class的实例

在这里插入图片描述

实操获取

public class Test{
   public static void main(String[] args) throws ClassNotFoundExcepion{
    Person person = new Student();
    System.out.println("这个人是" + person.name);
    
    //方式一:通过对象获取
    Class c1 = person.getClass();
    System.out.println(c1.hashcode());

    //方式二:forname获取
    Class c2 = Class.forname("com.reflection.Student")
    System.out.println(c2.hashcode());
    
    //方式三:通过类名.class获得
    Class c3 = Student.class;
    System.out.println(c3.hashcode());

  }

}

class Person{...}
class student extends Person{...}

4)关于类加载器

在这里插入图片描述

//获得类的信息
public class Test {
   public static void main(String[] args) throws ClassNotFoundException {
     class c1 = Class.forname("com.kuang.reflection.User");
     User user = new user();
     c1 = user.getclass();

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

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

     fields = c1.getDeclaredFields();
     for(Field field : fields){
       System.out.println(field);
      
     }
    
     //获得类的方法
     Method[] methods = c1.getMethods();
     for(Method method : methods){
       System.out.println("正常的"+method);
     }
    methods = c1.getDeclaredMethods();
    for(Method method : method){
       System,out.println("getDeclaredMethods"+method);
    }
    
    //获取指定方法
    Method getName = c1.getMethod("getName",null);//获取getName这个方法  getname方法没有参数
    Method setName = c1.getMethod("setName",String.class);
    //这里要丢一下参数,编译器才知道你要什么方法   
    //这里是调用setname的String重载,所以要丢一个String.class进去
    System.out.println(getName);
    System.out.println(setName);
   }

   //获得指定构造器
   Constructor[] constructors = c1.getConstructors();
   for(Constructor constructor : constructors){
      System.out.println(constructors);
   }
}

  //获得指定的构造器
  Constructor declaredConstructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
  System.out.println(declaredConstructor);

5)通过反射创建对象

在这里插入图片描述

public class Test{
public static void main(String[] args) throws ClassNotFoundException,IllegalAccessException{
 //获取class对象
 Class c1 = Class.forname("com.reflection,User");

 //1.普通创建一个对象
 User user = (user)c1.newInstance(); //本质是调用了类的无参构造
 System.out.println(user);
 
  //2.获得指定的构造器创建对象
  Constructor declaredConstructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
  User user2 = (user)constructor.newInstance("陈帅",001,18);  //有参构造
  System.out.println(user2);
  }
}

在这里插入图片描述

User user3 = (User)c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName",String.class);

//invoke:激活
//(对象,“方法的值”)
setName.invoke(user3,"陈帅");
System.out.println(user3.getName());

//通过反射操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");

//不要直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true);
name.setAccessible(true);
name.set(user4,"陈帅牛逼");
System.out.println(user4.getName());

在这里插入图片描述
实操

public class xingneng {
    //普通方法调用
    public static void test() {
        user user = new user();
        long starTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endtime = System.currentTimeMillis();
        System.out.println("普通方法执行10次"+(endtime-starTime)+ "ms");
    }

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

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

        long endtime = System.currentTimeMillis();
        System.out.println("反射方法执行10次"+(endtime-starTime)+ "ms");
    }

    //反射方法调用 关闭检测
    public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        user user = new user();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);
        long starTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }

        long endtime = System.currentTimeMillis();
        System.out.println("反射方法执行10次"+(endtime-starTime)+ "ms");
    }

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        test();
        test2();
        test3();
    }
}

程序运行结果
在这里插入图片描述
所以关闭检测可以提升程序的效率

6)反射操作泛型

在这里插入图片描述
在这里插入图片描述

7)反射操作注解

getAnnotations

getAnnotation

在这里插入图片描述

七、多线程

1、实现多线程

多线程在我目前开发中用的不算多,这里知识简单的梳理一下多线程的知识点。
实现 多线程的方法在Java中有两种,一种是继承thread类,还有一种方法就是重写runable方法

1)、继承thread类

这种方法就是写一个类来继承thread类,在这个类中还需要写一个run方法来运行这个线程,然后在主类中就可以创建这个线程然后启动该线程。以代码为例


class Thread1 extends Thread{
//创建一个类继承thread类
	private String name;
    public Thread1(String name) {
       this.name=name;
    }
	public void run() {
	//需要在该线程里面执行的方法
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "运行  :  " + i);
            try {
                sleep((int) Math.random() * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
       
	}
}

//主类
public class Main {
 
	public static void main(String[] args) {
		Thread1 mTh1=new Thread1("A");//创建一个线程的对象
		Thread1 mTh2=new Thread1("B");
		mTh1.start();//启动该线程
		mTh2.start();
 
	}
 
}

在线程运行的时候,需要注意下:两个线程启动时,在处理机上是并发运行的,因此线程输出的顺序并不确定。(所以在做PTA上面的题可能多提交几遍说不定就可以了。)

2) 重写Runable接口

具体需要子类实现Runable接口,然后重写里面的run方法就可以了。

class Thread2 implements Runnable{
//继承
	private String name;
 
	public Thread2(String name) {
		this.name=name;
	}
 
	@Override
	public void run() {//重写run方法
		  for (int i = 0; i < 5; i++) {
	            System.out.println(name + "运行  :  " + i);
	            try {
	            	Thread.sleep((int) Math.random() * 10);
	            } catch (InterruptedException e) {
	                e.printStackTrace();
	            }
	        }
		
	}
	
}

public class Main { 
	public static void main(String[] args) {
		new Thread(new Thread2("C")).start();//在主类中创建这个线程并且启动
		new Thread(new Thread2("D")).start();
	}
 
}

线程有好几种状态,如: 阻塞状态,准备状态等等,这一部分的内容以及关于线程的调度问题具体请参照操作系统部分

2、多线程常用的函数

1) start() 函数

主要应用于在主类中启动该线程。(需要先new 一个多线程的对象。

2) sleep()函数

sleep(long millils) 在指定的毫秒数内让线程休眠

3) join()函数

等待该线程的终止

4) yield()函数

暂停当前正在执行的线程对象,让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会

5) setPriority()函数

更改线程的优先级

6) interrupt()函数

向线程发出一个中断信号,让线程在无限等待的时候能够抛出,从而结束线程(并不是中断哪个线程)

7) wait()函数

Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify是针对已经获取了Obj锁进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){…}语句块内。

3、线程同步

1)、synchronized关键字

  • synchronized关键字的作用域有二种:
  1. 是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
  2. 是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
  • 除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/区块/},它的作用域是当前对象;

  • synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;

总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值