第一章:线程与多线程

1 2 10章是重点,3-9统称Servlet(有电子书资源)
李玮玮,智能设备方向,java基础,计算机组成原理都可以问问题。

Serviet是运行再服务器端小程序,主要负责业务逻辑操作。学完后可以实现一个简单网站。

1章	线程和多线程
1.	相关概念
程序 静态的概念
进程 
线程 
2.	线程生命周期:新建、就绪(可执行状态)、运行、死亡、阻塞
3.	创建线程2种方法
1)	继承Thread类
2)	实现Runnable接口
区别:1 继承Thread类不能再继承其他类,实现简单,不方便资源共享
			2实现Runnable接口还可以继承其他类,便于功能扩展,便于资源共享
4.	启动线程:start()
5.	其他的方法:
sleep(毫秒数)yield()线程让步、
join()join(毫秒值)
属性:name 存储线程名称  getName()    setName(“”)
priority  范围(1~10getPriority()  setPriority()
得到线程对象方法:this 仅限于用在Thread类中
							Thread.currentThread()  通用的方法
6.线程同步synchronized
1) 给方法加锁 (权限修饰符之后  返回值之前)
2) 给当前对象加锁 synchronized(this){  }
3) 给类的所有对象加锁 synchronized(.class){  }
4) 给属性加锁 synchronized(new().属性)
7. 死锁必要条件
互斥、请求和保持、不可剥夺、环路等待
8. 死锁出现的情况
相互排斥、部分分配、缺少优先级、



1.线程简介


1.1程序、进程、线程

  • 程序是一段静态的代码,是应用软件执行的蓝本

  • 进程 * 是程序的一次动态执行过程 *,它对应了从代码加载、执行至执行完毕 的一个完整过程,这个过程也是进程本身从产生、发展至消亡的过程 , 一个完整程序对应一个进程

  • 线程 * 是比进程更小的执行单位 *。进程在其执行过程中,可以产生多个线程 ,形成多条执行线索,每条线索,即每个线程也有它自身的产生、存在和 消亡的过程,也是一个动态的概念

一个进程至少包含一个线程。
在这里插入图片描述

1.1.1 Java中的线程

Java中的线程 :

  • 每个Java程序都有一个默认的主线程 –
  • 当JVM加载代码发现main方法之后,就会立即启动一个线程,这个线程称 为主线程

主线程的特点: 一般情况下main方法就是主线程

  • 是产生其他子线程的线程 (树干与树干的分支,一段时间内生长同时的)
  • 不一定是最后完成执行的线程
  • 主线程与子线程结束没有关系,主线程不一定最后完成执行,可能是子线程,主线程只负责启动子线程。
  • 进程的结束前提是所有线程都结束。

1.1.2 单线程与多线程
  • 如果main方法中没有创建其他的线程,那么当main方法执行完最后一条语 句,JVM就会结束Java应用程序——单线程
  • 如果main方法中又创建了其他线程,那么 JVM 就要在主线程和其他线程之 间轮流切换(CPU分配的时间), JVM 要等程序中所有线程都结束之后才结束程序——多线程

1.1.3 多线程的优势
  • 减轻编写交互频繁、涉及面多的程序的困难
  • 程序的吞吐量会得到改善
  • 由多个处理器的系统,可以并发运行不同的线程 (否则,任何时刻只有一个线 程在运行)
    • 同时:多个任务都执行。并行:多个程序交互运行
  • “同时”执行是人的感觉,在线程之间实际上轮换执行

1.2线程的应用场景

1.2.1 多线程什么场合下被使用呢? –
  • 想要同时处理多件事:单线程处理不了的,必须使用多线程。(类似于分身术,打扫卫生。多件事)
  • 多个线程分解大任务:用单线程可以做,但是使用多线程可以更快。(类 似于左右开弓,双手写字,一件事)

1.2.2线程的生命周期

五个状态:新建、就绪、运行、 阻塞、死亡
仅仅运行状态与阻塞状态的线程是活的。

  1. new关键词创立线程对象。
  2. 启动线程执行用start()方法启动执行。成为就绪状态(可运行状态,等待cpu分配时间)
  3. cpu分配时间,自动调用Run(),成为运行状态,
  4. 由于某种原因,无法继续运行,处于阻塞状态。

在这里插入图片描述


1.3线程状态介绍

  • 新建状态:线程对象已经创建,还没有在其上调用start() 方法 •

  • 可运行状态:当线程调用start方法,但调度程序还没有把 它选定为运行线程时线程所处的状态 •

  • 运行状态:线程调度程序从可运行池中选择一个线程作为 当前线程时线程所处的状态。这也是线程进入运行状态的 唯一方式

  • 等待/阻塞/睡眠状态:其共同点是:线程仍旧是活的,但是 当前没有条件运行。它是可运行的,当某件事件出现,他可 能返回到可运行状态 •

  1. 等待:等着主人说什么时候扫地
  2. 睡眠:主人觉得辛苦让睡觉半小时,知道多长时间不能工作 (不运行最短时间)。
  3. 阻塞:扫到一半簸箕没了。阻塞是这几种的统称。
  • 死亡状态:当线程的run()方法完成时就认为它死去。线程 一旦死亡,就不能复生。 一个死去的线程上调用start()方 法,会抛出java.lang.IllegalThreadStateException异常


2.Java中创建多线程

2.1定义任务

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

1.

通过继承Thread类来创建线程
public class xianCheng {
	public static void main(String[] args) {
		System.out.println("开始");
		//定义类,继承Thread类  
		MyThread t1=new MyThread();
		MyThread t2=new MyThread();
		//启动线程执行
//		t1.start();
//		t2.start();
t1,t2同时执行,作为子线程		


		t1.run();//做为方法进行执行
		t2.run();//有序,最后才打印结束
		System.out.println("结束");
	}
}


class MyThread extends Thread{	
	@Override
	public void run() {//方法体定义了线程的功能
		for(int i=1;i<11;i++) {
			System.out.println(i+"    ");
		}		
	}	
}

在这里插入图片描述

public class xianCheng {
	public static void main(String[] args) {
		System.out.println("1111");
		MyRunnable num=new MyRunnable();
		Thread list1=new Thread(num);
		Thread list2=new Thread(num);
		list1.start();
		list2.start();
		System.out.println("2222");

		
	}
}

class MyRunnable implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(i+"   ");
			睡眠一秒钟
			获取当前线程对象,通用方法
			Thread t=Thread.currentThread();
			try {
				t.sleep(1000);				
			}catch(InterruptedException e) {
				e.printStackTrace();
			}			
		}
	}
}

在这里插入图片描述

2.1.2.创建线程的方式对比
  • 继承Thread类实现多线程

    • 优点:编写简单,如果需要访问当前线程直接使用this即可获得当前线程.
    • 缺点:因为线程类已经继承了Thread类,不能再继承其他的父类 •
  • 实现Runnable接口

    • 优点:线程类只实现了Runable接口,还可以继承其他的类. 这种方式可以多 个线程共享同一个目标(target)对象,非常适合多个相同线程来处理同一份资 源的情况,从而可以将代码和数据分开,形成清晰的模型,较好地体现了面向 对象的思想
    • 缺点:编程稍微复杂,需要访问当前线程,必须使用Thread.currentThread() 方法
  1. • 线程的名字,一个运行的线程总有一个名字,JVM给的名 字或者我们自定义的名字,通过setName()方法设置 •
class MyThread extends Thread{	
	@Override
	public void run() {//方法体定义了线程的功能
		String name=this.getName();
		System.out.println("当前名称为    "+name);
		
		for(int i=1;i<11;i++) {
			System.out.println(i+"    ");
			//睡眠1秒钟,单位毫秒(1000)
		}		
	}	
}
public class xianCheng {
	public static void main(String[] args) {
		System.out.println("开始");
		MyThread t1=new MyThread();
		MyThread t2=new MyThread();
		t1.start();//同时执行,作为子线程
		t2.start();
		
		
获取主线程对象
		Thread t=Thread.currentThread();		
获取主线程名称
		String name=t.getName();
		System.out.println("name==   "+name);
结果为:name==   main
设置线程名字
		t,setName("hahahaha");
	}
}
  1. 获取当前线程对象的方法:Thread.currentThread() •
  2. 在一个程序里多个线程只能保证其开始时间,而无法保证 其结束时间,执行顺序也无法确定•
  3. 一个线程的run方法执行结束后,该线程结束 •
  4. 一个线程只能被启动一次 •
  5. 线程的调度是JVM的一部分,在一个CPU的机器上,一次 只能运行一个线程。
  6. JVM线程调度程序决定实际运行哪个 处于可运行状态的线程。采用队列形式

2.2线程中的常用方法

  1. start():启动线程,让线程从新建状态进入就绪队列排队 •
  2. run():线程对象被调度之后所执行的操作 •
  3. sleep():暂停线程的执行,让当前线程休眠若干毫秒 •
  4. currentThread():返回对当前正在执行的线程对象的引用 •
  5. isAlive():测试线程的状态,新建、死亡状态的线程返回 false•
  6. interrupt():“吵醒”休眠的线程,唤醒“自己” •
  7. yield():暂停正在执行的线程,让同等优先级的线程运行 •
  8. join():当前线程等待调用该方法的线程结束后,再排队等待 CPU资源 •
    再run()方法中,等待父亲run()方法调用后,通过t1.join()可以使得t1快于他的兄弟首先执行(t1是run的孩子)
  9. stop():终止线程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


2.3线程的优先级

主线程优先级默认是5
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3.1.多线程的问题

多线程程序在设计上最大的困难在于各个线程的控制流彼 此独立,使得各个线程之间的代码是乱序执行的,而且各 个线程共享资源,所以多线程会带来线程调度、同步、死 锁等一系列的问题

2.3.2.资源协调(synchronized )

产生问题的原因在于对共享数据访问的操作的不完整性 •

Java引入了对象互斥锁的概念,来保证共享数据操作的完 整性,从而避免上述问题
在这里插入图片描述
在这里插入图片描述
第三种,对对象的属性加锁,
synchronized(对象。属性)1
第四种:对类得所有属性枷锁

在这里插入图片描述



3.多线程的同步和死锁

  • 当两个或两个以上的线程在执行过程中,因争夺资源而造成 了互相等待,并且若无外力作用,它们都将无法推进下去的 现象称为系统处在死锁状态或系统产生了死锁 –
  • 资源占用是互斥的,当某个线程提出申请资源后,使得有关线程在无外力协 助下,永远分配不到必需的资源而无法继续运行
产生死锁的必要条件
  • 互斥条件:指线程对所分配到的资源进行排它性使用 –
  • 请求和保持条件:指线程已经保持至少一个资源,但又提出了新的资源请求 –
  • 不可剥夺条件:进程已获得的资源,在未使用完之前,不能被剥夺,只能在 使用完时由自己释放 –
  • 环路等待条件:指在发生死锁时,必然存在一个线程—资源的环形链

猜你喜欢

转载自blog.csdn.net/qq_44627608/article/details/104392431