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~10)getPriority() 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线程的生命周期
五个状态:新建、就绪、运行、 阻塞、死亡
仅仅运行状态与阻塞状态的线程是活的。
- new关键词创立线程对象。
- 启动线程执行用start()方法启动执行。成为就绪状态(可运行状态,等待cpu分配时间)
- cpu分配时间,自动调用Run(),成为运行状态,
- 由于某种原因,无法继续运行,处于阻塞状态。
1.3线程状态介绍
-
新建状态:线程对象已经创建,还没有在其上调用start() 方法 •
-
可运行状态:当线程调用start方法,但调度程序还没有把 它选定为运行线程时线程所处的状态 •
-
运行状态:线程调度程序从可运行池中选择一个线程作为 当前线程时线程所处的状态。这也是线程进入运行状态的 唯一方式
-
等待/阻塞/睡眠状态:其共同点是:线程仍旧是活的,但是 当前没有条件运行。它是可运行的,当某件事件出现,他可 能返回到可运行状态 •
- 等待:等着主人说什么时候扫地
- 睡眠:主人觉得辛苦让睡觉半小时,知道多长时间不能工作 (不运行最短时间)。
- 阻塞:扫到一半簸箕没了。阻塞是这几种的统称。
- 死亡状态:当线程的run()方法完成时就认为它死去。线程 一旦死亡,就不能复生。 一个死去的线程上调用start()方 法,会抛出java.lang.IllegalThreadStateException异常
2.Java中创建多线程
2.1定义任务
2.1.1 Java中两种创建线程的方式
通过继承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() 方法
- • 线程的名字,一个运行的线程总有一个名字,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");
}
}
- 获取当前线程对象的方法:Thread.currentThread() •
- 在一个程序里多个线程只能保证其开始时间,而无法保证 其结束时间,执行顺序也无法确定•
- 一个线程的run方法执行结束后,该线程结束 •
- 一个线程只能被启动一次 •
- 线程的调度是JVM的一部分,在一个CPU的机器上,一次 只能运行一个线程。
- JVM线程调度程序决定实际运行哪个 处于可运行状态的线程。采用队列形式
2.2线程中的常用方法
- start():启动线程,让线程从新建状态进入就绪队列排队 •
- run():线程对象被调度之后所执行的操作 •
- sleep():暂停线程的执行,让当前线程休眠若干毫秒 •
- currentThread():返回对当前正在执行的线程对象的引用 •
- isAlive():测试线程的状态,新建、死亡状态的线程返回 false•
- interrupt():“吵醒”休眠的线程,唤醒“自己” •
- yield():暂停正在执行的线程,让同等优先级的线程运行 •
- join():当前线程等待调用该方法的线程结束后,再排队等待 CPU资源 •
再run()方法中,等待父亲run()方法调用后,通过t1.join()可以使得t1快于他的兄弟首先执行(t1是run的孩子) - stop():终止线程
2.3线程的优先级
主线程优先级默认是5
2.3.1.多线程的问题
多线程程序在设计上最大的困难在于各个线程的控制流彼 此独立,使得各个线程之间的代码是乱序执行的,而且各 个线程共享资源,所以多线程会带来线程调度、同步、死 锁等一系列的问题
2.3.2.资源协调(synchronized )
产生问题的原因在于对共享数据访问的操作的不完整性 •
Java引入了对象互斥锁的概念,来保证共享数据操作的完 整性,从而避免上述问题
第三种,对对象的属性加锁,
synchronized(对象。属性)1
第四种:对类得所有属性枷锁
3.多线程的同步和死锁
- 当两个或两个以上的线程在执行过程中,因争夺资源而造成 了互相等待,并且若无外力作用,它们都将无法推进下去的 现象称为系统处在死锁状态或系统产生了死锁 –
- 资源占用是互斥的,当某个线程提出申请资源后,使得有关线程在无外力协 助下,永远分配不到必需的资源而无法继续运行
产生死锁的必要条件
- 互斥条件:指线程对所分配到的资源进行排它性使用 –
- 请求和保持条件:指线程已经保持至少一个资源,但又提出了新的资源请求 –
- 不可剥夺条件:进程已获得的资源,在未使用完之前,不能被剥夺,只能在 使用完时由自己释放 –
- 环路等待条件:指在发生死锁时,必然存在一个线程—资源的环形链