多线程
程序,进程,线程:
程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期
如:运行中的QQ,运行中的MP3播放器
程序是静态的,进程是动态的 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域。
线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。
若一个进程同一时间并行执行多个线程,就是支持多线程的。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小 。
一个进程中的多个线程共享相同的内存单元/内存地址空间-》它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患。
使用多线程的优点?
背景:以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方 法),肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?
何时需要多线程?
程序需要同时执行两个或多个任务。
程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。需要一些后台运行的程序时。
多线程程序的优点:
1. 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。 2. 提高计算机系统CPU的利用率
3. 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。
创建线程的2个方式
方式1 :继承 Thread类
示例:
public class TestThread{
public static class MyThread extends Thread{
@Override
public void run(){
System.out.printf("%s线程运行中\n",Thread.currentThread().getName());
}
}
public static void main(String[]args) {
MyThreadmyThread = new MyThread();
System.out.printf("在线程 %s 中启动 myThread\n",Thread.currentThread().getName());
myThread.start();// 注意,不要调用 run 方法
}
}
运行结果:
在线程 main 中启动myThread
Thread-0 线程运行中
可以看到, Java 入口函数 main 函数所在线程名为 main,我们一般称之为主线程。而我们自定义的线程,线程名是Thread-序号。上面的工具类Utils中的log方法用到了 Thread.currentThread().getName() 获取线程名称。
两个注意:
[if !supportLists]1. [endif]启动线程,要用 start 方法,而不是 run 方法。因为 run 方法是暴露给开发者写业务逻辑的,不会开启新线程。
[if !supportLists]2. [endif]一个线程对象只能启动一次,再次启动时会报错。
// 一个线程对象只能启动一次,再次启动时会报错。
public class TestThread{
public static class MyThread extends Thread{
@Override
public void run(){
Utils.log("线程运行中");
}
}
public static void main(String[]args) {
MyThreadmyThread = new MyThread();
Utils.log("启动线程");
myThread.start();
Utils.sleep(200);
myThread.start();
}
}
执行结果:
[main ][17:45:38.480]启动线程
[Thread-0 ][17:45:38.492]线程运行中
Exception inthread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
at TestThread.main(TestThread.java:15)
方式2:实现 Runnable 接口
示例:
public class TestThread{
public static void main(String[]args) {
ThreadmyThread = new Thread(new Runnable(){
@Override
public void run(){
Utils.log("线程运行中");
}
});
Utils.log("启动线程");
myThread.start();
}
}
或者简化为 lambda 形式:
public class TestThread{
public static void main(String[]args) {
ThreadmyThread = new Thread(()-> Utils.log("线程运行中"));
Utils.log("启动线程");
myThread.start();
}
}
运行结果示例:
[main ][17:55:42.383]启动线程
[Thread-0 ][17:55:42.395]线程运行中
自定义线程名称
使用 setName方法可以自定义线程名称。
示例:
public class TestThread{
public static void main(String[]args) {
Threadt1 = new Thread(()->{
Utils.log("t1线程运行中");
});
Threadt2 = new Thread(()->{
Utils.log("t2线程运行中");
});
Utils.log("主线程: 自定义线程名");
t1.setName("自定义线程名");
Thread.currentThread().setName("自定义主线程名");
Utils.log("主线程: 启动线程t1, t2");
t1.start();
t2.start();
}
}
运行结果:
[main ][18:29:45.381]主线程: 自定义线程名
[自定义主线程名 ][18:29:45.396]主线程: 启动线程t1, t2
[自定义线程名 ][18:29:45.396] t1线程运行中
[Thread-1 ][18:29:45.396] t2线程运行中
常用类
字符串相关的类:String
在 java 中,枚举类型是一种特殊数据类型,能够为一个变量定义一组预定义的常量。变量必须等于为其预定义的值之一。
String的特性
lString类:代表字符串。Java 程序中的所有字符串字面值(如"abc" )都作 为此类的实例实现。
lString是一个final类,代表不可变的字符序列。l字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。 lString对象的字符内容是存储在一个字符数组value[]中的。
public final class String
implements java.io.Serializable,Comparable, CharSequence {/** Thevalue is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash;// Default to 0
String对象的创建
String str ="hello";
//本质上this.value
= new char[0]; String s1 = new String();
//this.value = original.value;
String s2 = newString(String original);//this.value
= Arrays.copyOf(value, value.length);
String s3 = newString(char[] a);
String s4 = newString(char[] a,int startIndex,int count);
JDK8中新日期时间API
java.time – 包含值对象的基础包java.time.chrono – 提供对不同的日历系统的访问
java.time.format – 格式化和解析时间和日期 java.time.temporal – 包括底层框架和扩展特性
java.time.zone – 包含时区支持的类
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。 它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区
相关的信息。
ØLocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。ØLocalTime表示一个时间,而不是日期。ØLocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示 法,也就是公历。
枚举类
枚举类的使用
l枚举类的实现
ØJDK1.5之前需要自定义枚举类ØJDK 1.5 新增的enum 关键字用于定义枚举类
l若枚举只有一个对象, 则可以作为一种单例模式的实现方 式。
l 枚举类的属性
Ø枚举类对象的属性不应允许被改动, 所以应该使用private final 修饰
Ø枚举类的使用 private final 修饰的属性应该在构造器中为其赋值
Ø若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的 传入参数。
自定义枚举类
1. 私有化类的构造器,保证不能在类的外部创建其对象2. 在类的内部创建枚举类的实例。声明为:publicstatic final
3. 对象如果有实例变量,应该声明为privatefinal,并在构造器中初始化
[if !vml]
[endif]
Java集合
Java 集合可分为 Collection 和 Map 两种体系
ØCollection接口:单列数据,定义了存取一组对象的方法的集合üList:元素有序、可重复的集合 üSet:元素无序、不可重复的集合
Ø Map接口:双列数据,保存具有映射关系“key-value对”的集合
Collection接口
lCollection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法 既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
lJDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List) 实现。
l在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都 当成 Object 类型处理;从JDK 5.0 增加了泛型以后,Java 集合可以记住容 器中对象的数据类型。
Collection接口方法:
、添加Ø add(Objectobj)
Ø addAll(Collection
coll)
2、获取有效元素的个数 Ø int
size()
3、清空集合Ø void
clear()
4、是否是空集合Ø boolean
isEmpty()
5、是否包含某个元素Ø boolean
contains(Object obj):是通过元素的equals方法来判断是否是同一个对象Øboolean containsAll(Collection c):也是调用元素的equals方法来比较的。拿两个集合的元素挨个比较。
6.删除
Ø boolean remove(Object obj) :通过元素的equals方法判断是否是
[if !supportLists]· [endif] 要删除的那个元素。只会删除找到的第一个元素
Ø boolean removeAll(Collection coll):取当前集合的差集
7、取两个集合的交集Ø boolean
retainAll(Collection c):把交集的结果存在当前集合中,不影响。
8、集合是否相等
Ø booleanequals(Object obj)
9、转成对象数组
Ø Object[]toArray()
10、获取集合对象的哈希值
Ø hashCode()
11、遍历
Ø iterator():返回迭代器对象,用于集合遍历
泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
泛型方法
你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
下面是定义泛型方法的规则:
[if !supportLists]· [endif]所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
[if !supportLists]· [endif]每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
[if !supportLists]· [endif]类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
[if !supportLists]· [endif]泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
实例
下面的例子演示了如何使用泛型方法打印不同字符串的元素:
public classGenericMethodTest
{
// 泛型方法printArray
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] )
{
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = {1, 2, 3, 4, 5};
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
Character[] charArray = {'H', 'E', 'L', 'L', 'O'};
System.out.println( "整型数组元素为:");
printArray( intArray );// 传递一个整型数组
System.out.println( "\n双精度型数组元素为:");
printArray( doubleArray );// 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:");
printArray( charArray );// 传递一个字符型数组
}
}
[if !supportLineBreakNewLine]
[endif]
编译以上代码,运行结果如下所示:
整型数组元素为:
1 2 3 4 5
双精度型数组元素为:
1.1 2.2 3.3 4.4
字符型数组元素为:
H E L L O
有界的类型参数:
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
实例
下面的例子演示了"extends"如何使用在一般意义上的意思"extends"(类)或者"implements"(接口)。该例子中的泛型方法返回三个可比较对象的最大值。
public classMaximumTest
{
// 比较三个值并返回最大值
public static <T extends Comparable<T>> T maximum(T x, T y, T z)
{
T max = x;// 假设x是初始最大值
if ( y.compareTo( max ) > 0){
max = y;//y 更大
}
if ( z.compareTo( max ) > 0){
max = z;// 现在 z 更大
}
return max; // 返回最大对象
}
public static void main( String args[] )
{
System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
3, 4, 5, maximum( 3, 4, 5) );
System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7) );
System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
"apple", "orange", maximum( "pear", "apple", "orange") );
}
}
[if !supportLineBreakNewLine]
[endif]
编译以上代码,运行结果如下所示:
3, 4 和 5 中最大的数为5
6.6, 8.8 和 7.7 中最大的数为8.8
pear, apple 和 orange 中最大的数为pear
泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
实例
如下实例演示了我们如何定义一个泛型类:
public classBox {
privateT t;
public void add(T t) {
this.t = t;
}
public T get() {
returnt;
}
public static void main(String[] args) {
Box integerBox =newBox();
Box stringBox =newBox();
integerBox.add(new Integer(10));
stringBox.add(new String("菜鸟教程"));
System.out.printf("整型值为 :%d\n\n", integerBox.get());
System.out.printf("字符串为 :%s\n", stringBox.get());
}
}
[if !supportLineBreakNewLine]
[endif]
编译以上代码,运行结果如下所示:
整型值为:10
字符串为 :菜鸟教程
类型通配符
1、类型通配符一般是使用?代替具体的类型参数。例如List<?>在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
import java.util.*;
public classGenericTest {
public static void main(String[] args) {
List name =newArrayList();
List age =newArrayList();
List number =newArrayList();
name.add("icon");
age.add(18);
number.add(314);
getData(name);
getData(age);
getData(number);
}
public static void getData(List data) {
System.out.println("data :" + data.get(0));
}
}
[if !supportLineBreakNewLine]
[endif]
输出结果为:
data :icon
data :18
data :314
解析: 因为getData()方法的参数是List>类型的,所以name,age,number都可以作为这个方法的实参,这就是通配符的作用
2、类型通配符上限通过形如List
extends Number>来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
import java.util.*;
public classGenericTest {
public static void main(String[] args) {
List name =newArrayList();
List age =newArrayList();
List number =newArrayList();
name.add("icon");
age.add(18);
number.add(314);
//getUperNumber(name);//1
getUperNumber(age);//2
getUperNumber(number);//3
}
public static void getData(List data) {
System.out.println("data :" + data.get(0));
}
public static void getUperNumber(List data) {
System.out.println("data :" + data.get(0));
}
}
[if !supportLineBreakNewLine]
[endif]
输出结果:
data :18
data :314
解析: 在(//1)处会出现错误,因为getUperNumber()方法中的参数已经限定了参数泛型上限为Number,所以泛型为String是不在这个范围之内,所以会报错
3、类型通配符下限通过形如List<?
super Number>来定义,表示类型只能接受Number及其三层父类类型,如Objec类型的实例。
Io流
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
Java
IO原理
lI/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
lJava程序中,对于数据的输入/输出操作以“流(stream)”的 方式进行。
ljava.io包下提供了各种“流”类和接口,用以获取不同种类的 数据,并通过标准的方法输入或输出数据。
反射机制
JavaReflection
lReflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。
l加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看 到类的结构,所以,我们形象的称之为:反射。
补充:动态语言vs静态语言
1、动态语言 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以
被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运 行时代码可以根据某些条件改变自身结构。 主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。
2、静态语言 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、 C++。
Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动 态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。 Java的动态性让编程的时候更加灵活!
反射相关的主要API
l java.lang.Class:代表一个类ljava.lang.reflect.Method:代表类的方法ljava.lang.reflect.Field:代表类的成员变量ljava.lang.reflect.Constructor:代表类的构造器 l......