一、常用类
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. 关于这几个字符串的区别
String | StringBuffer | StringBuilder |
---|---|---|
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.常用的数学方法
- 三角函数方法
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));
}
}
- 指数函数方法
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));
}
}
- 取整函数
//Math类里的取整函数
public static double ceil( double a);//向上取整
public static double floor( double a);//向下取整
public static double rint( double a);//返回和参数最接近的整数,如果同样接近,则结果取整数
- 取最大值,最小值,绝对值函数方法
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)枚举类的使用
- 枚举类的理解:类的对象只有有限个,确定的,就为枚举类
- 当需要定义一组常量时,强烈建议使用枚举类
- 如果枚举类中只有一个对象,则可以作为单例模式的实现方式
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关键字的作用域有二种:
- 是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
- 是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
-
除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/区块/},它的作用域是当前对象;
-
synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。