华清远见-重庆中心-JAVA高级阶段技术总结

String类

  • String是一个类,属于数据类型中的引用类型。
  • 在创建字符串对象时,先在字符串常量池中搜索要创建的字符串对象是否存在,如果存在则直接使用,这时,如果String a和String b创建了相同的字符串对象,那么a==b,因为它们用的是同一个地址;不存在就创建一个新的字符串对象。
  • 在比较字符串的值是否相同时,不建议使用==判断,==判断的是内存地址。建议使用String类重写的equals方法进行判断,这里比较的是字面值。
  • 使用+拼接的两个字符串对象,是先拼接了再去字符串常量池中搜索是否存在拼接后的字符串对象。
常用方法名返回值作用
length()int得到字符串长度
trim()String去除字符串首尾的所有空格
toCharArray()char[ ]将字符串转换为字符数组
equals(String str)boolean判断两个字符串是否相同
charAt(int index)char得到字符串指定索引上的字符
indexOf(String str)int得到字符串中某个字符串第一次出现的索引,如果不存在,返回-1
lastIndexOf(String str)int得到字符串中某个字符串最后一次出现的索引,如果不存在,返回-1
contains(字符序列)boolean判断某个字符串是否在原字符串中出现
substring(int begin)String从指定索引开始截取字符串至末尾
substring(int begin,int end)String截取[begin,end)区间内的字符串
split(String regex)String[ ]

根据指定的字符串regex去分割原字符串。

如果指定内容在末尾,n个指定字符串能得到n个分割后的字符串(不包含末尾上的指定字符串后的无效字符);如果不在末尾则得到n+1个分割后的字符串(在头部会包括头部前的无效的字符)

String.valueOf(参数)String将任意参数转换为字符串。通常用于原始类型转换为字符串。

StringBuilder类

可变字符串的一个类,是非线程安全的,建议在单线程环境下使用。

构造方法名作用
StringBuilder()创建一个大小为16的字符串数组,表示一个空白字符。
StringBuilder(String str)创建一个str长度+16的字符数组后,将str添加到其中。
普通方法名作用
append(Object obj)将任意类型的参数添加到原可变字符串的末尾
delete(int start,int end)删除[start,end)区间内的字符
deleteCharAt(int index)删除index索引上的字符
insert(int index,Object obj)在索引index上插入obj
replace(int start,int end,String str)将[start,end)区间内的字符替换为str
reverse()反转字符串(相当于倒序)

StringBuffer类

可变字符串的一个类,是线程安全的,建议在多线程环境下使用。

转换

//String转换为可变字符串
StringBuilder sb=new StringBuilder(String str);

//可变字符串转换为String
StringBuilder sb1=new StringBuilder("方法1");
String str1=String.valueOf(sb1);

StringBuilder sb2=new StringBuilder("方法2");
String str2=sb.toString();

StringBuilder sb3=new StringBuilder("方法3");
String str3=sb+"";

注意

这三个类都是被final修饰的类,不能被继承。

频繁更改字符串时,不要使用String类,会创建很多字符串对象浪费内存;如果要频繁更改字符串,使用StringBuilder类或StringBuffer类。

System类

它的属性和方法都是静态的。它的构造方法是私有的,不能创建对象。

属性和方法作用
System.out获取打印输出流PrintStream对象,用于控制台打印信息
System.in获取输入流InputStream对象,用于获取输入的信息
System.err获取打印输出流PrintStream对象,用于控制台打印异常信息
System.exit(int statues)终止虚拟机运行,statues为0表示正常终止
System.currentTimeMillis()获取从1970.1.1 0:0:0至今过了多少毫秒。返回值为long类型
System.arraycopy(原数组,原数组起始位,目标数组,目标数组起始位,原数组要复制的元素数量)将原数组中指定位置长度的元素复制到新数组指定位置上

Date类

构造方法名作用
Date()创建当前瞬间对应的日期对象
Date(long l)创建指定瞬间对应的日期对象
普通方法名作用
getTime()得到对应Date对象表示的毫秒数
setTime(long l)设置Date对象的毫秒数
after(Date when)判断调用日期对象是否在when之后
before(Date when)判断调用日期对象是否在when之前

SimpleDateFormat类

构造方法

SimpleDateFormat(String pattern);   创建一个指定日期模板的格式化对象

日期模板

特殊字符作用
yyyy
MM
dd
HH小时
mm分钟
ss

E

星期

常用方法

方法名作用
format(Date date)将Date对象按日期模板转换为字符串
parse(String str)将满足日期模板的字符串转换为Date对象
String patten = "yyyy/MM/dd HH:mm:ss E";
simpleDateFormat sdf = new SimpleDateFormat(patten);

String format = sdf.format(new Date());

Date date = sdf.parse("2000/5/3 2:1:3 星期一");

Calendar类

日历字段

作用
Calender.YEAR年份
Calender.MONTH月份(0~11表示1~12月)
Calender.DATE日期
Calender.DAY_OF_WEEK星期几(1~7表示周日到周六)
Calender.HOUR12进制小时
Calender.HOUR_OF_DAY24进制小时
Calender.MINUTE分钟
Calender.SECOND
Calender.DAY_OF_MONTH本月第几天
Calender.DAY_OF_YEAR本年第几天
Calender.WEEK_OF_MONTH本月第几周
Calender.WEEK_OF_YEAR本年第几周

常用方法

方法名作用
get(int field)根据日历字段获取对应的值
getTime()获取对应的Date对象(Calendar对象转换为Date对象)
getMaximum(int field)获取指定日历字段支持的最大值
getActualMaximum(int field)获取指定日历字段在当前日期下的实际最大值
set(int field,int value)将指定的日历字段设置为指定值
set(int year,int month,int date)同时设置日历对象的年月日
setTime(Date date)将Date对象作为参数设置日历对象的信息

包装类

  • 包装类就是原始类型对应的类型,通常用于字符串与原始类型之间的转换。
  • 包装类就是八大原始类型首字母大写,其中需要注意的是int和char,int对应的包装类为Interger,char对应的包装类为Character。
  • 包装类被final修饰,不能被继承。
  • Character的构造方法只有一个,参数为char类型;其余包装类除了参数为自己本身的原始类型外还有参数为String的构造方法。
  • 除了Character类,其余类都有静态方法parse原始类型(String str)。
  • 除了Boolean类,其余包装类都有MAX_VALUE和MIN_VALUE这两个静态属性,用于获取对应类型支持的最大最小值
  • 所有包装类都重写了toString()方法,用于将包装类对象转换为String对象

转换

字符串转原始类型

使用对应的包装类调用parse原始类型(字符串)

String num="123";
byte b = Byte.parseByte(num);
short s = Short.parseShort(num);
int i = Integer.parseInt(num);
long l = Long.parseLong(num);
float f = Float.parseFloat(num);
double d = Double.parseDouble(num);
boolean flag = Boolean.parseBoolean(num);

原始类型转字符串

//+拼接一个空白字符串
int num1 = 123;
String str1 = num1 + "";
//调用toString()方法
int num2 = 123;
Integer integer = new Integer(num2);
String str2 = integer.toString();
//String.valueOf()
int num3 = 123;
String str3 = String.valueOf(num3);

装箱拆箱

手动

//装箱
int i = 123;
Integer integer = Interger.valueOf(i);
//拆箱
Integer integer = new Integer(123);
int i = integer.intValue();

自动

//装箱
Integer anInt = 345;
//拆箱
int i = anInt;

自动装箱方式创建包装类对象,赋值范围在byte范围[-128,127]内,将这个值保存在缓冲区中,如果多个对象使用同一个数值,共享这个数据,使用同一个地址,使用==判断结果为 true。引用类型对象比较值是否相同时,建议使用重写的equals方法,==判断的只是内存地址。

异常

异常大体上分为Error错误和Exception异常。假如出现xxxxError是无法通过额外的代码解决,只能修改源码;如果出现xxxxException,可以通过额外的代码去解决。

Exception异常主要分为两个类型,一个是运行时异常RuntimeException,可以通过编译,可以不 用处理,运行时可能抛出异常对象;另一个是编译时异常,无法通过编译,必须处理异常后才能编译运行。

运行时异常名出现场景
NullPointerException 空指针异常用空对象null调用属性或方法
ArrayIndexOutOfBoundsException 数组下标越界异常使用数组时,下标超出范围
NumberFormatException 数字格式异常使用包装类调用parse方法做转换时,无法将参数转换。
InputMismatchException 输入不匹配异常使用Scanner接收控制台输入时,不满足接收的类型。
ClassCastException 对象转型异常Person p = (Person)Object obj;
ArithmeticException 算术运算异常0当分母
编译时异常名出现场景
SQLException 数据库SQL相关异常操作数据库时
IOException 输入输出流异常使用流对象时
FileNotFoundException 文件未找到异常方法的参数为文件时

处理异常

try-catch-finally语句

try{
    //可能出现异常的代码
}catch(异常类 异常对象){
    //如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}catch(异常类 异常对象){
    //如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}finally{
    //无论程序是否会抛出异常,都要执行的代码
}

throws关键字

在方法参数部分之后,添加  throws 异常类型1,异常类型2...

throws和throw

  • throws表示用于声明方法有可能出现的异常。使用时写在方法的小括号之后。
  • throw用于手动抛出异常对象。使用时,写在方法体中,常用于满足某种情况时,强制中断程序。用法:throw 异常对象;

集合

集合的根接口为Collection接口和Map接口,位于java.util包中。

Collection接口

该接口有两个核心子接口:List和Set。 这两个接口都可以保存一组元素,List接口保存元素时,有序可重复的;Set接口保存元素时,是无序不重复的。

常用方法名返回值作用
add(Object obj)boolean将元素添加到集合中
size()int获取集合中的元素数量
isEmpty()boolean判断集合是否为空
clear()void清空集合
contains(Object obj)boolean判断集合中是否存在指定元素
remove(Object obj)boolean移除集合中的指定元素

List接口

常用方法名返回值作用
get(int index)Object根据指定索引获取对应的元素
set(int index,Object obj)Object使用obj替换index上的元素,返回被替换的元素
add(int index,Object obj)void将obj添加到index上
remove(int index)Object移除指定索引的元素
indexOf(Object obj)int得到某元素第一次出现的索引,没有返回-1
lastIndexOf(Object obj)int得到某元素最后一次出现的索引,没有返回-1
subList(int from,int to)List截取[from,to)区间内的元素,返回子集合

ArrayList实现类

常用构造方法 说明
ArrayList()创建一个Object类型的空数组。在调用添加方法后,才会更改该数组大小为10
ArrayList(int initialCapacity)创建一个指定容量的Object数组,如果参数为负,会抛出IllegalArgumentException异常

ArrayList中的常用方法,就是Collection接口和List接口中定义的方法

LinkedList实现类

常用构造方法 说明
LinkedList()创建一个空链表

于LinkedList既实现了List接口,又实现了Deque接口,所以还有Deque接口中的一些方法

实现Deque接口的方法 说明
addFirst(Object obj)添加头元素
addLast(Object obj)添加尾元素
removeFirst()移除头元素
removeLast()移除尾元素
getFirst()得到头元素
getLast()得到尾元素
remove()移除头元素
pop()移除头元素
push(Object obj)添加头元素
peek()得到头元素
poll()移除头元素
offer(Object obj)添加尾元素

ArrayList和LinkedList

  • 这两个类都是List接口的实现类,保存的元素有序可重复,允许保存null
  • ArrayList采用数组实现,随机读取效率高,插入删除效率低,适合用于查询
  • LinkedList采用双向链表实现,插入删除时不影响其他元素,效率高,随机读取效率低,适合用于频繁更新集合

set接口

  • 无序集合,元素不可以重复,允许保存null,没有索引。
  • Set接口中没有自己定义的方法,都是继承于Collection接口中的方法

哈希码

  • 如果两个对象的hashCode不同,这两个对象一定不同
  • 如果两个对象的hashCode相同,这两个对象不一定相同

HashSet实现类

常用构造方法 说明
HashSet()创建一个空集合,实际是创建一个HashMap对象

HashSet中没有属于自定义的方法,都是重写了父接口Set和Collection中的方法。

TreeSet实现类

常用构造方法 说明
TreeSet()创建一个空集合,实际是创建一个TreeMap对象

能使用Collection和Set中的方法,除此之外,还有独有的方法

常用方法名作用
fisrt()得到集合中的第一个元素
last()得到集合中的最后一个元素
ceil(Object obj)得到比指定元素obj大的元素中的最小元素
floor(Object obj)得到比指定元素obj小的元素中的最大元素

Map接口

  • Map称为映射,数据以键值对的形式保存。保存的是键与值的对应关系。
  • 键称为Key,值称为Value,键不能重复,键允许出现一个null作为键,值无限制。
  • 键和值都是引用类型
常用方法名作用
size()得到键值对的数量
clear()清空所有键值对
put(Object key,Object value)向集合中添加一组键值对
get(Object key)在集合中根据键得到对应的值
remove(Object key)/remove(Object key,Object key)根据键或键值对移除
keyset()获取键的集合
values()获取值的集合
containsKey(Object key)判断是否存在某个键
containsValue(Object value)判断是否存在某个值
entrySet()得到键值对的集合

HashMap实现类

常用构造方法 说明
HashMap()创建一个空的映射集合,默认大小为16,加载因子为0.75

常用方法参考Map中的方法

遍历集合中元素的方式

遍历List集合

ArrayList<String> nameList = new ArrayList();
nameList.add("Tom");
nameList.add("Jerry");
nameList.add("LiHua");
nameList.add("Danny");
//方式一:普通for循环
for (int i = 0; i < nameList.size(); i++) {//从0遍历到size()
    String name = nameList.get(i);//通过get(int index)获取指定索引的元素
    System.out.println(name);
}
//方式二:增强for循环
for (String name : nameList) {
    System.out.println(name);
}
//方式三:迭代器
//Collection类型的集合对象.iterator(),获取迭代器
Iterator<String> iterator = nameList.iterator();
// iterator.hasNext()判断集合中是否还有下一个元素
// iterator.next();获取下一个元素
while (iterator.hasNext()) {
    String name = iterator.next();
    System.out.println(name);
}

遍历Set集合

Set hs = new HashSet();
hs.add(123);
hs.add("hello");
hs.add(null);
hs.add(987);
//方式1:增强for循环
for(Object o : hs){
    System.out.println(o);
}
//方式2:迭代器
Iterator<Object> it = hs.iterator();
while(it.hasNext()){
    System.out.println(it.next());
}

遍历Map集合

Map<Integer, User> hm = new HashMap<>();
User u1 = new User("admin", "123123");
User u2 = new User("tom", "123123");
User u3 = new User("jerry", "123123");
hm.put(1001, u1);
hm.put(1002, u2);
hm.put(1003, u3);
//遍历hashMap
for (Integer id : hm.keySet()) {
    System.out.println(id + "\t" + hm.get(id).getUsername());
}
//得到当前hashmap对象中的所有键值对的集合
Set<Map.Entry<Integer, User>> entries = hm.entrySet();
//遍历键值对
for (Map.Entry<Integer, User> entry : entries) {
    System.out.println(entry);
}

泛型

集合类或接口 集合变量名 = new 集合实现类();

List<String> list = new ArrayList();
//当前集合只能保存String类型的元素
list.add("sdfsdf");
//list.add(123);//无法添加
List<Integer> list2 = new ArrayList();
list2.add(123);

Collections集合工具类

常用方法 说明
Collections.shuffle(List list)打乱List集合中元素的顺序
Collections.sort(List list)对List集合中的元素进行排序,元素必须实现Comparable接口
Collections.swap(List list,int a,int b)交换List集合中元素的索引
Collections.replaceAll(List list,Object oldObj,Object newObj)替换List集合中的旧元素为新元素
Collections.reverse(List list)将List集合中的元素反转
Collections.fill(List list , Object obj)使用指定元素填充List集合
Collections.rotate(List list , int n)将集合中最后n个元素放在最前
Collections.max(Collection col)/min(Collection col)得到集合中的最大/最小值,集合中的元素必须实现Comparable接口

集合与数组的转换

集合转换为数组

//使用Collection接口中的toArray()方法
Object[] obj = 集合对象.toArray();
List<Integer> list = new ArrayList();
list.add(123);
list.add(63);
list.add(3);
Integer[] nums =(Integer[]) list.toArray();

数组转换为集合


int[] nums ={11,2,66,3,6,21};
List list = new ArrayList();
for(int i:nums){
    list.add(i);
}

一组数据转换为集合

//使用Arrays工具类中的asList(一组数据)方法
//通常将数组中的数据直接作为参数
List<String> strings = Arrays.asList("XX", "aa", "qq", "xx");

文件类File

常用构造方法 说明
File(String pathName)根据文件的完整路径创建File对象
File(String parent,String child)根据文件的父目录路径和自身路径创建File对象
File(File parent,String child)根据文件的父目录对应的File对象和自身路径创建File对象
常用方法说明
exists()判断文件是否存在
isFile()判断是否为文件
isDirectory()判断是否为目录
getName()获取文件名
getPath()获取文件相对路径
getAbsolutePath()获取文件绝对路径
getParent()获取父目录的名称
getParentFile()获取父目录对象
lastModified()获取最后一次修改时间对应的毫秒数
length()获取文件所占字节
isHidden()判断文件是否隐藏
delete()删除文件或空目录
renameTo(File newFile)将原文件重命名且移动到指定目录
mkdir()创建目录
list()获取某个目录下的第一层子文件的名称的数组
listFiles()获取某个目录下的第一层子文件对象的数组

  • 用于表示计算机硬盘与内存之间传输数据的通道。
  • 将内存中的数据存入到硬盘中,称为写write,也称为输出Output。
  • 将硬盘中的数据存入到内存中,称为读read,也称为输入Input。

字节输入流

InputStream FileInpuStream、ObjectInputStream

字节输出流

OutputStream FileOutputStream、ObjectOutputStream

字符输入流

Reader FileReader、BufferedReader、OutputStreamWriter

字符输出流

Writer FileWriter、BufferedWriter、InputStreamReader

按方向分类

  • 输入流:InputStream、Reader 将硬盘中的数据读取到内存中
  • 输出流:OutputStream、Writer 将内存中的数据写入到硬盘中 

按类型分类

  • 字节流:InputStream、OutputStream 读写非文本类型文件。如图片、音视频、其他文件等。
  • 字符流:Reader、Writer 读写纯文本类型文件。如txt、md等

如要将硬盘中某个txt文件中的内容读取到程序中,使用Reader

如要将硬盘中的某个图片读取到程序中,使用InputStream

如要将程序中的文本写入到硬盘中为txt类型文件时,使用Writer

如要将程序中的数据写入到硬盘中为非文本文件时,使用OutputStream

流的四个父类的特点

  • 这四个父类都是在java.io包下,都是抽象类,不能直接创建其对象,使用其子类创建对象
  • 这四个父类中都定义了close()方法,用于关闭流对象,释放资源
  • 输入流(InputStream和Reader)都有read()方法读取数据到内存中,输出流都有write()方法写入数 据到硬盘中
  • 输出流(OutputStream和Writer)都有flush()方法,用于将流中的数据冲刷到硬盘中
  • 所有的流中,以Stream结尾,都是字节流,数据以字节传输;以Reader或Writer结尾的,都是字符流,数据以字符传输
  • 读取硬盘中的数据,使用输入流,读取的文件必须存在;将数据写入到硬盘中,使用输出流,文件可以不存在,但父目录必须存在。
  • 读入或写入文本时,使用字符流;读取或写入非文本时,使用字节流

FileInputStream文件字节输入流

常用构造方法 说明
FileInputStream(String pathName)根据文件名创建流对象
FileInputStream(File file)根据文件对象创建流对象
常用方法 说明
read()读取一个字节,返回读取到的字节
read(byte[] bytes)

按字节数组读取,返回读取到的字节数量,读取到的内容保存在字节数组中

close()关闭流对象

FileOutputStream文件字节输出流 

常用构造方法 说明
FileOutputStream(String pathname)根据文件名创建输出流对象,写入时覆盖原内容
FileOutputStream(String pathname,boolean append)根据文件名创建输出流对象,第二个参数为true,写 入时追加在原内容之后
FileOutputStream(File file)根据文件对象创建输出流对象,写入时覆盖原内容
FileOutputStream(File file,boolean append)根据文件对象创建输出流对象,第二个参数为true, 写入时追加在原内容之后
常用方法 作用
write(int i)写入一个指定字节
write(byte[] bytes)写入一个字节数组
write(byte[] bytes,int off,int len)写入字节数组中从off开始的len个字节
flush()将流中的数据冲刷到硬盘中
close()关闭流对象

注意

  • 在通过FileInputStream对象使用read(byte[] bytes)方法时,每次读取指定数组的字节,将读取到的字节保存在字节数组中,该方法返回读取到的字节数量。如果最后一次读取的字节数不足字节数组的大小时,只会将读取到内容覆盖数组中最前的几个元素。所以会导致读取到的内容多于实际内容。
  • 在通过FileOutputStream对象使用write(byte[] bytes)方法时,会将字节数组中的所有内容写入到输出流中,在最后一次写入时,可能会写入多余的内容。所以在写入时,最好使用write(byte[] bytes,int off,int lef)方法,表示将字节数组中的内容,从off开始写入len个。

FileReader文件字符输入流

常用构造方法 说明
FileReader(String fileName)根据文件名创建文件字符输入流对象
FileReader(File file)根据文件对象创建文件字符输入流对象
常用方法 作用
ready()判断是否还有下一个字符
read()读取下一个字符,返回读取到的字符
read(char[] chars)按字符数组读取,返回读取到的字符数量,读取到的字符保存在字符数组中
close()关闭流对象

FileWriter文件字符输出流

常用构造方法 作用
FileWriter(String fileName)按文件名创建字符输出流对象,覆盖写入
FileWriter(String fileName,boolean append)按文件名创建字符输出流对象,如果append为true, 表示追加写入
FileWriter(File file)按文件对象创建字符输出流对象,覆盖写入
FileWriter(File file,boolean append)按文件对象创建字符输出流对象,如果append为 true,表示追加写入
常用方法 作用
write(String str)按字符串写入
flush()将流中的数据冲刷到硬盘中的文件,必须调用该方法或close方法后,才能真正写入
close()关闭流对象

BufferedReader缓冲字符输入流

常用构造方法 作用
BufferedReader(Reader in)创建一个带有缓冲区(大小为8192的char数组)的字符输入流对象, 参数为Reader类型对象,Reader是抽象类,所以实际参数为 Reader的子类,如FileReader,在FileReader对象中定义要读取的文件
BufferedReader(Reader in,int size)创建一个指定缓冲区(字符数组)大小的字符输入流对象
常用方法 作用
ready()判断是否还有字符
readLine()读取整行字符
close()关闭流对象

BufferedWriter缓冲字符输出流

常用构造方法 说明
BufferedWriter(Writer writer)创建一个自带缓冲区的字符输出流对象,参数为一个Writer对象, Writer是一个抽象类,实际参数为Writer的子类,如FileWriter,在 FileWriter中定义要将输入写入的目标文件
BufferedWriter(Writer writer,int size)创建一个指定缓冲区大小的字符输出流对象
常用方法 作用
write(String str)写入字符串
newLine()换行
flush()冲刷流中的数据到硬盘
close()关闭流对象

ObjectOutputStream对象字节输出流(序列化)

被序列化的对象,必须要实现Serializable接口。

构造方法 说明
ObjectOutputStream(OutputStream os)创建一个对象字节输出流对象,参数为一个字节输出 流对象,由于OutputStream是抽象类,所以使用其子类,如FileOutputStream对象,在其中定义要写入的文件
常用方法 作用
writeObject(Object obj)将一个对象写入到本地文件中
close()关闭流对象

ObjectInputStream对象字节输入流(反序列化)

常用构造方法说明
ObjectInputStream(InputStream is)创建一个对象字节输入流对象,参数为一个字节输入流对 象,由于InputStream是抽象类,所以使用其子类,如 FileInputStream对象,在其中定义要读取的文件
常用方法 作用
readObject()读取序列化后的文件,返回类型为Object
close()关闭流对象

转换流

  • OutputStreamWriter 将字节输出流转换为字符输出流
  • InputStreamReader 将字节输入流转换为字符输入流
  • 转换流的使用 如果只提供了一个字节流,但要向其中写入或读取字符时,就可以使用转换流将字节流转换为字符流。 使用字符流读写字符时比字节流更方便。

Socket类和ServerSocket类

都属于Socket(套接字)对象,表示网络中的某个端点

  • Socket指普通端
  • ServerSocket指服务器端

进程和线程

进程Process

  • 进程就是操作系统中执行的程序。一个程序就是一个执行的进程实体。
  • 每个运行中的进程,都有属于它独立的内存空间,各个进程互不影响。

线程Thread

  • 线程是一个进程中的执行单元,一个进程中可以有多个线程。
  • 多个线程可以访问同一个进程中的资源。 每个线程都有一个独立的栈空间,这些线程所在的栈空间位于同一个进程空间中。

多线程

  • 如果一个进程中,同时在执行着多个线程,就称为多线程。 多线程可以提高程序执行效率。

Java中的线程Thread类

  • Java中,线程以对象的形式存在。
  • Thread类表示线程类

获取线程对象

  • 获取当前正在运行的线程对象
Thread ct = Thread.cuurentThread();
  • 创建一个线程对象
常用构造方法 说明
Thread()创建一个默认的线程对象
Thread(String name)创建一个指定名称的线程对象
Thread(Runnable target)将一个Runnable对象包装为线程对象
Thread(Runnable target,String name)将一个Runnable对象包装为线程对象同时设置线程名

线程常用方法

方法 作用
getId()获取线程id
getName()获取线程名,默认Thread-n
getPriority()获取线程优先级,默认为5
getState()获取线程状态
setName(String str)设置线程名
setPriority(int priority)设置线程优先级,范围在1-10,值越大越优先执行
isDaemon()判断线程是否为守护线程
setDaemon(boolean f)参数为true表示设置线程为守护线程
start()让线程进入就绪状态
run()线程获得执行权时执行的方法(线程要做的事情)
Thread.sleep(long m)设置当前线程休眠m毫秒
Thread.currentThread()获取当前执行的线程对象
Thread.yield()线程让步

实现多线程

方式一:继承Thread类

  1. 创建一个类,继承Thread类
  2. 重写Thread类中的run()方法
  3. 创建自定义的线程子类对象后,调用start()方法

方式二:实现Runnable接口

由于Java中是单继承,如果某个类已经使用了extends关键字去继承了另一个类,这时就不能再通过extends继承Thread实现多线程。 就需要实现Runnable接口的方式实现多线程。

  1. 自定义一个类,实现Runnable接口
  2. 重写run()方法,将多线程要执行的内容写在该方法中
  3. 创建Runnable接口的实现类对象
  4. 使用构造方法Thread(Runnable target)或Thread(Runnable target,String name)将上一步创建的Runnable实现类对象包装为Thread对象

方式三:使用匿名内部类

如果不想创建一个Runnable接口的实现类,就可以使用匿名内部类充当Runnable接口的实现类

线程的生命周期

线程的初始化到终止的整个过程,称为线程的生命周期。

新生状态

当线程对象被创建后,就进入了新生状态。

就绪状态

当某个线程对象调用了start()方法后,就进入了就绪状态。 在这个状态下,线程对象不会做任何事情,只在等他CPU调度。

运行状态

当某个线程对象得到CPU时间片(CPU执行这个线程的机会所给的时间),则进入运行状态,开始执行 run()方法。不会等待run()方法执行完毕,只会在指定的时间内尽可能地执行run()方法。只要调用玩run()方法后,就会再进入就绪状态。

阻塞状态

如果某个线程遇到了sleep()方法或wait()方法时,就会进入阻塞状态。 sleep()方法会在指定时间后,让线程重新就绪。 wait()方法只有在被调用notify()或notifyAll()方法唤醒后才能重新就绪。

终止状态

当某个线程的run()方法中的所有内容都执行完,就会进入终止状态,意味着该线程的使命已经完成。

多线程访问同一个资源

出现问题

由于线程调用start()方法后,就进入就绪状态。如果获得了CPU时间片,就开始调用run()方法,调用 run()方法后,就会再次进入就绪状态,不会等待run()方法执行完毕,所以在线程A执行run()方法的时候,线程B也开始执行了,这样就会出现数据共享的问题。 因为现在所有的线程都是异步(同时)执行。

如何解决

让线程同步(排队)执行即可。这样一来,某个线程执行run()方法的时候,让其他线程等待run()方法的内容执行完毕。

synchronized关键字

这个关键字可以修饰方法或代码块

  • 修饰方法

        写在方法的返回值之前,这时该方法就称为同步方法。

  • 修饰代码块

        写在一个独立的{}前,这时该段内容称为同步代码块。

原理

  • 每个对象默认都有一把"锁",当某个线程运行到被synchronized修饰的方法时,该对象就会拥有这把锁,在拥有锁的过程中,其他线程不能同时访问该方法,只有等待其结束后,才会释放这把锁。
  • 使用synchronized修饰后的锁称为"悲观锁"。
  • 方法被synchronized修饰后,称为同步方法,就会让原本多线程变成了单线程(异步变为同步)。

死锁

定义两个线程类,线程A先获取资源A后,在获取资源B;线程B先获取资源B后,再获取资源A。 如果对资源A和资源B使用了synchronized进行同步,就会在线程A获取资源A的时候,线程B无法获取资源A,相反线程B在获取资源B的时候,线程A无法获取资源B,所以两个线程都不会得到另一个资源。

解决方式

方式一

让两个线程获取资源的顺序保持一致。

方式二

让两个线程在获取资源A和B之前,再获取第三个资源,对第三个资源使用synchronized进行同步,这样 某个线程在获取第三个资源后,将后续内容执行完毕,其他线程才能开始执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值