JavaSE基础--多线程入门

多线程

1、并发与并行

并发:指两个/多个事件在同一时间段发生(交替进行)
并行:指两个/多个事件在同一时刻发生(同时发生,同时进行)

2、进程和线程

硬盘:永久存储ROM
内存:临时存储RAM

  • 所有应用程序都要进入内存执行,进入到内存的程序叫进程
  • 一个程序至少有一个进程,一个进程可以包含多个线程
  • 线程属于进程,是进程中的一个执行单元,负责程序执行
  • 单核心单线程cpu:在多个线程间做高速切换,效率低
  • 4核心8线程cpu:可同时执行8个线程,在多个任务间高速切换,是单核cpu速度的8倍
3、线程调度
  • 分时调度:所有线程轮流使用cpu,平均分配时间
  • 抢占式调度:优先让优先级高的线程使用CPU,优先级相同时,会随机选择一个。(任务管理器可设置优先级)
4、创建线程类

主线程:执行主(main)方法的线程
单线程程序:只有一个线程,执行从main开始,从上到下依次执行。
JVM执行main方法,main方法会进入到栈内存
JVM会找操作系统开辟一条main方法通向CPU的执行路径,cpu就可以通过这个路径来执行main方法

创建新线程的两种方法:

  1. 将类声明为Thread的子类,该子类应重写Thread的run方法。创建实例并调用start方法->run
public class ThreadTest extends Thread{
		public void run() {
			System.out.println("创建了线程");
		}
		public static void main(String[] args) {
			ThreadTest t=new ThreadTest();
			t.start();
		}
}
  1. 声明实现Runnable的类,然后实现run方法,并分配该类实例,在创建Thread时作为一个参数传递并启动。new Thread®
public class Runnable01  implements Runnable{
	public  void run() {
		System.out.println(Thread.currentThread().getName()+"建立了新线程");
	}
}
public class DemoRunnable {
	public static void main(String[] args) {		
	//创建Runnable接口的实现类对象
			Runnable01 r=new Runnable01();
			//创建新线程,传入Runnable接口的实现类
			Thread t=new Thread(r);
			//调用start方法开启新线程,实现新方法
			t.start();
	}
}
  • 多线程内存:start()方法执行时,会开辟新的栈空间来执行run()方法
  • 好处:多个线程间互不影响(在不同的栈空间)
  • 实现Runnable接口创建多线程程序的好处:
    1、避免了程序的单继承性;实现该接口后,还能继承其他的类或实现其它接口。
    2、增强了程序的扩展性(降低耦合性),把设置线程任务(run())和开启新线程(start())进行分离。
5、匿名类方式实现线程的创建

作用:简化代码

//使用匿名内部类的方法,实现多线程
	new Thread(new Runnable() {
			public void run() {
		    	System.out.println(Thread.currentThread().getName()+"建立了新线程");
			}
	}).start();

使用lambda表达式简化

//使用lambda表达式
	new Thread(()-> {
			System.out.println(Thread.currentThread().getName()+"建立了新线程");
	}).start();

线程安全

1、线程安全

多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。

2、解决线程安全问题

为保证每个线程都能正常执行原子操作,Java引入了线程同步机制:

  1. 同步代码块
  2. 同步方法
  3. 锁机制
3、同步代码块
  • 格式:
synchronized(锁对象){
    可能会出现线程安全问题的代码(访问了共享数据的代码)
}
  • 注意事项
  1. 代码块中的锁对象,可使用任意的对象
  2. 但是必须保证多个线程使用的锁对象是同一个
  3. 锁对象作用:把同步代码块锁住,只让一个线程在其中执行
  • 同步技术的原理:使用了一个锁对象,这个锁对象叫同步锁,也叫对象锁,也叫对象监视器。
    比如t0抢到cpu执行权,执行run()方法时,遇到synchronized代码块会检查是否有锁对象,若有,就会获取锁对象,进入到同步中执行。 t1抢到cpu执行权时,执行run()方法,遇到了synchronized代码块会检查是否有锁对象,发现没有,t1会进入阻塞状态,直到t0执行完同步中的代码,将锁对象归还给同步代码块时t1才能获取锁对象进入到同步中执行。
  • 总结:同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去同步。
4、使用同步方法
  1. 把访问了共享数据的代码抽取出来,放到一个方法中
  2. 在方法上添加synchronized修饰符
  • 格式
修饰符 synchronized 返回值类型 方法名(参数列表){
    可能会出现线程安全问题的代码
}
  • 同步方法的锁对象是实现类对象,也就是this。
  • 静态的同步方法(static):锁对象是本类的class属性,class文件对象(反射),不是this,因为静态方法优于对象,this是创建对象后产生的。
5、Lock锁

Lock接口实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作

  1. 在成员位置创建一个Reentrantlock对象
  2. 在可能出现安全问题的代码前调用lock获取锁
  3. 在可能出现安全问题的代码后调用unlock释放锁

线程状态:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OZpoTPBz-1575130359472)(“C:\Users\11974\Desktop\笔记截图\线程状态.png”)]

进入计时等待(Time-Waiting)两种方式:

  1. 使用sleep(long m):在毫秒值结束之后,会进入Runnable/Blocked状态
  2. 使用wait(long m):在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,进入到Runnable/Blocked状态
  3. notify():如果有多个线程任意唤醒一个
  4. notifyAll():唤醒所有等待的线程

等待唤醒机制

1、线程间通信

概念:多个线程在处理同一个资源,但处理的动作(线程任务)不同

2、等待唤醒机制

概念:多个线程间的一种协作机制

方法:wait()、notify()、notifyAll()

线程池

1、概念

容器–>集合(ArrayList、HashSet、LinkedList、HashMap

使用remove()和add()(以及类似方法)来使用或归还线程

在JDK1.5后,内置了线程池,避免频繁创建销毁线程。

2、优点

合理利用线程池的好处:

  1. 降低资源消耗,减少创建和销毁的次数,每个工作线程都可重复利用,可执行多个任务。
  2. 提高响应速度,任务到达时不需等待线程创建。
  3. 提高线程的可管理性,可根据任务数量调整池中工作线程的数目,防止因消耗过多内存使服务器崩溃。

Lambda表达式

1、函数式编程思想概述

函数式编程会尽量忽略面向对象的复杂语法-强调做什么,而不是以什么形式做。

2、冗余的runnbale代码
  1. 需要Runnable接口
  2. 创建实现了该接口的实现类
  3. 为省去定义一个实现类的麻烦,不得不使用匿名内部类
  4. 必须覆盖抽象run方法
  5. 但事实上只有方法体才是关键所在
3、Lambda表达式标准格式

适用于需要实现接口的类,同时需要重写的方法只有一个

一些参数+一个箭头+一段代码

(参数列表)->{重写方法的代码}

Lambda表达式:

  1. 使用Lambda必须有接口,且接口中有且只有一个抽象方法
  2. 使用Lambda必须具有上下文推断,有且只有一个抽象方法的接口,称为函数式接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值