回顾和多线程

一、知识回顾:

1.1 Java的基本语法

  1. 数据类型:基本数据类型和引用数据类型
  2. 运算符:算数、比较、逻辑、赋值、位、三目
  3. 表达式
  4. 顺序结构
  5. 分支结构(选择结构):if、switch
  6. 循环结构:for、while、do-while

1.2 Java:面向对象

  1. 最终目的:消除重复代码
  2. 核心:类和对象
  3. 特征:封装、继承、多态、抽象
  4. 关键字:this、super、public、private、void、static、interface、implements、final、class、default
  5. 抽象类和接口:类单继承、接口多实现

1.3 Java中的数组

  1. 概念:存储多个相同数据类型的数据结构

  2. 特点:长度固定

  3. 声明和初始化:数据类型[] 变量名 = 初始化(动态初始化、静态初始化)

  4. 索引:从0开始

  5. 算法:

    (1)排序算法

    (2)查找算法

  6. 多维数组:Java允许数组的元素又是一个数组

1.4 Java中的集合

  1. 概念:存储多个指定数据类型的元素
  2. 特点:长度可变。存储引用数据类型。存储基本数据类型需要使用到他们对应的包装类
  3. 种类:List、Set、Map
  4. 常用集合类:ArrayList、HashMap、TreeSet等
  5. 泛型:引用类型的占位符。(好处:代替了Object,避免了转型(向上转型、向下转型))

1.5 Java中的流(为了持久化存储数据)

  1. File类:Java中操作文件或目录的类。

    常用的方法:创建、删除、重命名、获取

  2. 流:Stream 数据通信的通道。

  3. 分类

    (1)根据功能分:

    ①Java中的节点流文件流(操作文件的数据都是跟文件有关)如:FileXXX;内存流(操作的数据都是跟数组有关)如ByteXXX

    ②Java中的过滤流:缓冲流、对象六、数据流、转换流等等

    (2)根据单位分:字节流、输出流

    (3)根据方向分:输入流、输出流

    输入流:read、skip(跳过)

    输出流:write、flush(刷新)

1.6 Java中的异常

  1. 异常分类:

    (1)错误(Error):人为不可解决

    (2)异常(Exception):

    ①运行时异常(RuntimeException):代码在运行阶段,显示的异常。如IndexOutBoundException

    ②编译时异常:代码在编译阶段,显示的异常。如IOException

二、Java中的反射

2.1 反射是什么

反射机制是Java程序在运行中,动态获取类的信息(方法、属性、注解等),并且还可以调用类的属性和方法。这种动态获取类的信息、以及动态调用对象的方法和属性的行为就i叫反射。

反射就是可以获取类的信息和执行对应的方法。

2.2 反射可以用来做什么

  1. 运行时获取类中的属性

  2. 运行时获取类中的方法

  3. 运行时创建类的对象

  4. 运行时执行类中的方法

  5. 运行时校验属性是否属于某个类

  6. 实现动态代理

2.3 反射怎么用

  1. 通过反射实现类中的属性、方法的获取,还可以运行类中的方法。

  2. 创建Class对象的三种方式

    (1)类名.class
    (2)Class.forName
    (3)对象名.getClass

  3. 代码演示:获取类中的属性

    public static void main(String[] args) {
    	//1.创建反射对象--Class
    	Class<Student> clz=Student.class;
    	//2.获取Student类中的属性
    	//公共属性,包含继承属性
    	Field[] arrF=clz.getFields();
    	//所有属性,不包含继承的属性
    	Field[] arrF2=clz.getDeclaredFields();
    	//3.显示 获取到的属性
    	System.err.println("公共属性,包含继承属性:"+Arrays.toString(arrF));
    	System.err.println("所有属性,不包含继承的属性:"+Arrays.toString(arrF2));
    }
  4. 代码演示:获取类中的方法

    public static void main(String[] args) {
    	//1.获取反射对象
    	Class<Student> clz=Student.class;
    	//2.获取对象中的方法
    	//公共方法,包含继承方法
    	Method[] arrM=clz.getMethods();
    	//所有方法,不包含继承方法
    	Method[] arrM2=clz.getDeclaredMethods();
    	//3.显示对应的方法
    	System.err.println("公共方法:"+Arrays.toString(arrM));
    	System.err.println("所有方法:"+Arrays.toString(arrM2));
    }
  5. 代码演示:通过反射执行类中的方法

    public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    	//1.获取反射对象
    	Class<Student> clz=Student.class;
    	//执行公共方法
    	//2.获取要运行的方法对象
    	Method m=clz.getDeclaredMethod("eat");
    	//3.创建对应的对象
    	Student s=clz.newInstance();
    	//4.执行方法
    	/*
    	 * invoke 参数说明:
    	 * 1.方法对应的对象
    	 * 2.方法需要的参数,可变参数*/
    	m.invoke(s);
    	
    	//执行私有方法
    	Method rm=clz.getDeclaredMethod("run");
    	//设置 是否过滤访问校验  私有方法或属性,必须设置过滤访问校验
    	rm.setAccessible(true);
    	rm.invoke(s);
    }

三、进程和线程

3.1 进程

  1. 概念:软件在运行时的一种状态,会占用CPU、内存等资源。即可理解为正在运行的程序。

  2. 特点:独立性、动态性、并发性

3.2 线程

  1. 概念:代码的执行路径,是进程的一部分。一个进程可以有多个线程,每个线程都可以执行自己的内容或者多个线程共同执行一个任务。也就是说有了多线程,就可以同时干多件事情

  2. 线程是CPU的最小调度单位

  3. CPU可以很快的在多个线程间切换

  4. 运行时的线程,随时都可以被CPU挂起

  5. 线程的抢占发生在任意时期

3.3 进程和线程的区别

  1. 一个程序可以有多个进程

  2. 一个进程可以有多个线程,但是必须要有个主线程

  3. 进程间不能共享资源,但是线程之间可以共享资源

四、线程的体验和创建方式

Java中的main方法其实就是主线程,main内部的代码执行都是主线程在执行

我们手动创建的方法都叫子线程

4.1 线程初体验

public static void main(String[] args) {
		//1.创建线程接口的对象  匿名内部类-实例化 接口、抽象类
		Runnable rb=new Runnable() {
			@Override
			public void run() {
				System.err.println("我是子线程-"+
			Thread.currentThread().getName());
			}
		};
		//2.创建线程对象,并定义线程要做的事情
		Thread td=new Thread(rb);
		//3.启动线程
		//td.start();//才是子线程在运行
		
		td.run();//这样的话,代码的运行就是主线程运行。
		System.err.println("主线程-"+Thread.currentThread().getName());
	}

4.2 线程的说明

  1. Java中的线程类:Thread

  2. Java中的线程都需要接口,线程接口:Runnable。

    这个接口里只有一个方法:run

  3. 每次在写子线程时,都需要在run方法内部实现自己要做的事

  4. 启动线程用的是start方法

4.3 线程的创建方式

线程常用的的三种创建方式

(1)实现Runnable接口

(2)自定义类实现Thread类的子类,重写run方法

(3)实现Callable接口(JDK1.8新特性)

4.4 创建线程方式一:实现Runnable接口

  1. 采用匿名内部类,直接完成接口的实例化,并重写run方法

  2. 自定义实现接口

    package com.qfedu.b_thread;
    /**
     * 实现Runnable接口
     */
    public class MyRunnable implements Runnable{
    
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		for (int i = 0; i < 100; i++) {
    			System.out.println("子线程-数羊" + i);
    		}
    	}
    

}



在这里插入代码片


   ```java
   package com.qfedu.b_thread;
   /**
    * main方法测试
    */
   public class CreateThread01 {
   	public static void main(String[] args) {
   		// 1. 创建接口的实现类
   		MyRunnable mr = new MyRunnable();
   		// 2. 创建线程对象
   		Thread td = new Thread(mr);
   		// 3. 启动线程
		td.start();
   	}
   }

敲黑板:实际上我们可以通过匿名内部类来实现Runnable接口

4.5 创建线程方式二:继承Thread类

创建类继承Thread,并重写run方法

public class HelloThread  extends Thread{
	@Override
	public void run() {
		System.err.println(" 继承线程类 实现子线程");
	}
}
public static void main(String[] args) {
		//1.实例化自定义线程类对象
		HelloThread ht=new HelloThread();
		//2.启动线程
		ht.start();
}

4.6 创建线程方式三:使用Callable实现

说明:Callable接口是JDK1.8新版本推出的线程创建方式,线程可以带返回值

操作步骤:

(1)实现Callable接口,并指定线程的返回值类型

(2)创建FutureTask对象

(3)创建线程对象,并传递任务对象

(4)启动线程

(5)获取线程的返回值

public class MyCallable implements Callable<Integer>{
	@Override
	public Integer call() throws Exception {
		System.err.println("子线程,带返回值的");
		return new Random().nextInt(10);
	}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
		//1.创建 Callable接口的实现类对象
		MyCallable mc=new MyCallable();
		//2.创建任务对象
		FutureTask<Integer> ft=new FutureTask<Integer>(mc);
		//3.创新线程对象
		Thread td=new Thread(ft);
		//4.启动线程
		td.start();
		//5.获取线程的返回值 只有在线程执行结束之后才会返回
		System.err.println("返回值:"+ft.get());
	}

4.7 三种创建方式的区别及选用

  1. 继承Thread类

    编写简单,但由于Java的单继承特性,所以这种类无法在继承其他类,无法实现多个线程的资源共享

  2. 实现Runnable接口

    编写稍微复杂一点,接口可以多实现,还可以实现多个线程的资源共享,推荐使用。

  3. 实现Callable接口

    编码较为复杂,但是线程执行完之后有返回值

小结:开发中,创建线程时,如果要求线程存在返回值,使用Callable;不需要线程返回值时,使用Runnable接口的实现

五、线程的状态

5.1 线程的状态(生命周期)

线程有五大状态,分别是:新建、就绪、运行、阻塞、销毁

  1. 新建:当我们实例化线程对象的时候,就是新建

  2. 就绪:当我们调用现成的start方法之后,线程就会进入就绪状态

  3. 运行:线程获取CPU的调度之后,线程抢到时间片,可以用来运行自己的任务

  4. 阻塞:线程因为资源竞争,或主动方法调用,让线程进入阻塞状态。比如sleep()、wait()、join()、synchronized()

  5. 销毁:当线程的run方法执行结束之后,就会进入到销毁状态

敲黑板程序的结束是指内部的线程全部进入到销毁状态

回顾和多线程_第1张图片

六、线程的分类

6.1 线程的种类

  1. 线程分为:用户线程守护线程

  2. Java中默认的线程是用户线程

  3. 代码演示

    public static void main(String[] args) {
    		// 代码演示线程的类型 用户线程和守护线程
    		//默认的就是用户线程
    		Thread th=new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				// TODO Auto-generated method stub
    				System.err.println("子线程");
    			}
    		});
    		th.start();
    		//创建守护线程
    		Thread th2=new Thread(new Runnable() {
    					@Override
    					public void run() {
    						// TODO Auto-generated method stub
    						System.err.println("子线程--守护线程");
    					}
    				});
    		//设置当前的线程对象是否为守护线程,默认为false
    		th2.setDaemon(true);
    		//启动线程
    		th2.start();
    	}

6.2 用户线程和守护线程的区别

主线程和GC线程就是经典的用户和守护线程案例

守护线程的特点:当守护的用户线程销毁的时候,守护线程也会跟着销毁。无论守护线程是否执行结束都会随着用户线程一起销毁。

守护线程又叫后台线程

6.3 代码演示

当用户线程销毁的时候,会将自己未执行结束的守护线程一起销毁

public class LogRunable implements Runnable{

	@Override
	public void run() {
		//死循环
		while(true) {
			//间隔3秒 打印日志……
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("守护线程:记录日志中……");
		}
	}
}
public static void main(String[] args) {
		//演示 用户线程和守护线程
		//创建用户线程
		Thread td=new Thread(new Runnable() {
			
			@Override
			public void run() {
				//拥有守护线程
				Thread t=new Thread(new LogRunable());
				//设置为守护线程 守护的是当前的用户线程
				t.setDaemon(true);
				t.start();
				for(int i=1;i<10001;i++) {
					if(i%33==0&& i%77==0) {
						try {
							Thread.sleep(500);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						System.err.println("用户线程--"+i);
					}
				}
			}
		});
		//启动用户线程
		td.start();
	}

七、线程的优先级

7.1 优先级

线程的优先级就是线程获取CPU的概率,优先级别越高,获得CPU的概率越大

从小到大,1~10之间,10是优先级最高,默认的优先级是5

7.2 设置优先级

  1. 通过线程的setPriority设置线程的优先级

  2. 通过线程的getPriority获取线程的优先级

  3. 设置优先级需要在start之前

  4. 线程的优先级默认是5

八、线程练习

8.1 使用多线程模拟一个人的生活

小磊同学,看电视的同时可以玩游戏、还可以说话聊天。用多线程来描述。

代码演示:

public static void main(String[] args) {
		//三个线程-分别做不同的事情
		//匿名内部类 实现
		Thread td1=new Thread(new Runnable() {	
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.err.println("小磊在看电视--->爱情电视剧 泡沫剧");
			}
		});
		td1.start();
		
		Thread td2=new Thread(new Runnable() {	
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.err.println("小磊在玩游戏--->斗地主、俄罗斯方块、扫雷");
			}
		});
		td2.start();
		
		Thread td3=new Thread(new Runnable() {	
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.err.println("小磊在聊天--->单身男士喜欢的内容");
			}
		});
		td3.start();
		
	}

扩展——Lambda表达式

  1. Lambda是JDK8之后支持的一种简写模式,可以快速实现接口实例化

  2. 语法格式:(参数) -> {方法重写}

  3. 规则:

    (1)接口

    (2)接口中只能有一个抽象方法

    (3)Lambda表达式的结果是一个对象

  4. 代码演示

    public interface IEat {
    	void eat();
    }
    public static void main(String[] args) {
    		//1.基于Lambda表达式完成接口的实例化  
    		IEat ie=()->System.err.println("吃啥呢?");
    		ie.eat();
    }

你可能感兴趣的:(java,多线程)