多线程

线程和进程的概念

进程:一个程序的运行实例,正在进行的程序。通常来说一个程序对应着一个进程,它有独立的内存空间和系统资源。
线程:线程是CPU中运算和分派的基本单位,也是进程中运算/的基本单位。一个进程中可以有多个线程,一个线程可以独立完成一个顺序控制流程。
在这里插入图片描述

多线程和单线程的概念

单线程:如果程序中只有一个线程,那么称为单线程
多线程:如果程序中有多个线程,那么称为多线程

  1. 多线程在执行时不一定有单线程执行快。
  2. 多线程产生的根本原因也是它最根本的优势,就是我们能够在一个程序中,同时同时干多件事,可以充分利用CPU的资源。
  3. 其实多线程有两个概念,一种是指单核CPU的多线程,一种是指多核CPU的多线程
    单核CPU:同时只能执行一个线程,但同样可以实现多线程,这个多线程是“抢占式/交替”执行的。
    多核CPU:可进行交替执行,也可以实现真正的物理上的并行执行。

主线程

  • main()方法即为主线程入口
  • 产生其他子线程的线程
  • 必须最后完成执行,因为它执行各种关闭动作
    Java给我们准备了一个类,来支持我们进行多线程编程Thread类。
    在Java中每一个程序有且只有一个主线程,就是我们程序入口main方法。
public static void main(String[] args){
	// 通过线程类的静态方法 获取当前线程对象
	Thread currentThread = Thread.currentThread();
	// 通过Thread的getName()方法能获得线程的名称
	System.out.println("当前线程的名字是:"+currentThread.getName());
	// 有get必然有set方法
	currentThread.setName("MyThread");
	System.out.println(" 当前线程名字是:"+currentThread.getName());
}

线程的基本创建和启动

在Java中创建线程的两种方式

  • 继承java.lang.Thread类
  • 实现java.lang.Runnable接口

使用线程的步骤
①.定义线程—>②.创建线程对象—>③.启动线程—>④.终止线程

继承Thread类

  • 定义MyThread类继承Thread
  • 重写run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
public class MyThread extends Thread{
	// 重写run()方法
	public void run(){
		XXXXX
	}
}
// main方法调用定义的MyThread类
public static void main(String[] args){
		MyThread thread = new MyThread();
		thread.start();//启动线程
}

如果再创建第二个线程对象,这时候我们同样给其启动,会发现两个线程是交互执行的,并且没有什么规律这就叫做“CPU的抢占式调度”;

  • 多个线程交替执行,不是真正的“并行”
  • 线程每次执行时长由分配的CPU时间片长度决定
    在这里插入图片描述
    启动线程能否直接调用run()方法?

如果线程不调用start()那么不会开启线程,直接使用线程调用run()方法会是主线程调用run()方法,那么自然不会出现交替执行,只有一条main线程执行路径,属于单线程执行模式。
在这里插入图片描述
如果调用start()方法 那么就开启了子线程,这样主线程和子线程就开始交替执行,因为CUP再一个时间点只能执行一个线程,因此多个线程是交替执行的,分配的时间片长度不完全一致,可多可少,所以每次运行结果不同,CPU越快,那么分配效果越不好展现。
在这里插入图片描述

实现Runnable接口

  • 定义MyRunnable类实现Runnable接口
  • 实现run()方法,边写线程执行体
  • 创建线程对象,调用start() 方法启动线程

在这里插入图片描述

Thread 和 Runnable 两种方式的区别

实际上Thread类也实现了Runnable接口。实际开发中多是使用实现Runnable接口的方式。
继承Thread类

  • 编写简单,可直接操作线程
  • 适用于单线程

实现Runnable接口

  • 避免单继承局限性
  • 便于共享资源

线程的生命周期

在这里插入图片描述
每个Java程序至少由一个线程即主线程 main。当一个Java程序启动时,JVM会创建主线程,并在该线程种调用main()放法。
在执行new MyThread()之后此时线程处于创建状态,执行了start()方法之后,开启了第一个线程(默认线程名称为Thread-x,序号从0开始)此时该线程处于就绪状态
同样创建并开启第二个线程后,此时它也处于就绪状态。(故事:所有的人员必须全部准备好才能开始活动,这时候不会因为谁先准备号就谁先开始!)
当某个线程进入了run()方法这时候它就获得了CPU资源,此时进入运行状态。(谁先强到,谁加一分)
休眠或者等待输入(Scanner)时线程处于阻塞状态,释放了CPU资源然后再队列中等待阻塞解除,解除之后就又进入了就绪状态。
线程自然执行完毕,外部干涉终止线程,这时候属于线程死亡状态。

线程的调度

线程的优先级
线程的优先级的高低反映县城的重要或紧急程度,一般情况下,优先级越高线程获得CPU资源概率越大,线程的优先级由1~10表示,1最低,默认为5
线程休眠
让线程暂时睡眠指定时长,线程进入阻塞状态
睡眠时间过后线程再次进入运行状态

public static void sleep(long millis)

millis为休眠时长,以毫秒为单位
调用sleep()方法需处理InterruptedException异常

public class Wait{
	public static void bySec(long s){
	for(int i = 0;i < s;i ++){
		System.out.println(i + 1 + "秒");
		try{
			Thread,sleep(1000);
		}catch(InterruptedException){
			}
		}	
	}
}

线程强制运行
使当前线程暂停,等待其他线程结束后在进行
void join(long millis)
等待该线程运行结束的时间为millis毫秒。(该线程强制要运行的时间)
线程礼让
yueld()方法可以让当前正在执行的线程暂停,但它不会阻塞线程,它知识将该线程从运行状态转入就绪状态。

线程同步

同时有多个线程在执行,虽然它们是交替执行,但是速度切换很快,如果有一些资源被共享,可能导致资源出错。
线程并发
同一个资源被多个线程共享,可以通过“加锁”synchronized解决安全问题。

同步方法
public synchronized void saleTicket(){

}

同步代码块
synchronized(this){

}

常见的线程安全类型

StringBufferStringBuilder
它们再使用种没有区别,但是StringBuffer线程安全,而StringBuilder线程不安全,但是同理,线程安全效率就低,效率高线程就不安全。
HashMapHashtable
HashTable是线程安全的
HashMap是线程不安全的
ArrayListVector
Vertor是线程安全的
ArrayList是线程不安全的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值