一、多线程
进程的概述和多进程的意义
线程的概述和多线程的意义
JVM运行原理以及JVM启动的线程探讨
实现多线程
线程调度
线程控制
二、进程概述及多进程的意义
A:线程和进程
要想说线程,首先必须得聊聊进程,因为线程是依赖于进程存在的。
B:进程概述
什么是进程呢?通过任务管理器我们就可以看到进程的存在。
概念:进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。
C:多进程的意义
单进程计算机只能做一件事情。而我们现在的计算机都可以一边玩游戏(游戏进程),一边听音乐(音乐进程),
所以我们常见的操作系统都是多进程操作系统。比如:Windows,Mac和Linux等,能在同一个时间段内执行多个任务。
对于单核计算机来讲,游戏进程和音乐进程是同时运行的吗?不是。
因为CPU在某个时间点上只能做一件事情,计算机是在游戏进程和音乐进程间做着频繁切换,且切换速度很快,
所以,我们感觉游戏和音乐在同时进行,其实并不是同时执行的。多进程的作用不是提高执行速度,而是提高CPU的使用率。
线程概述及多线程的意义及并行和并发的区别
并发(concurrency)和并行(parallellism)是:
- 解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
- 解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
- 解释三:并行是在一台处理器上“同时”处理多个任务,并发是在多台处理器上同时处理多个任务。如 hadoop 分布式集群。
所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
三、多线程程序实现的方式1
public class MyThread extends Thread{
@Override
public void run() {
//这个run方法就是需要线程来执行的代码,一般耗时的操作,我们就会写在run方法里面,让线程去执行
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
-------------------------------------------------------------
public class MyTest3 {
public static void main(String[] args) {
MyThread th = new MyThread();
//开启线程,不是调用run方法,调用run()方法,就是你使用一个对象,调用一个方法,让这个方法执行而已,线程并没有开启
//th.run();
//正确开启线程的方式是,调用start() 开启线程,由线程去调用run()去执行run方法里面的代码
th.start();
//th.start(); 同一个线程不要多次开启,会抛异常
MyThread th2 = new MyThread();
th2.start();
}
}
获取和设置线程对象名称
如何获取main方法所在的线程名称呢?
public static Thread currentThread()//获取当前执行的线程
/**
* 我们现在是想获取主线程的名称,那么我们可不可以先获取到主线程,
如果我们能获取到主线程,那么我们就可以调用getName方法获取对应的名称.
* 如何获取主线程呢? public static Thread currentThread()返回对当前正在执行的线程对象的引用。
* -----------------------------------------------------------------
:Thread类的基本获取和设置方法
public final String getName()//获取线程名称
public final void setName(String name)//设置线程名称
其实通过构造方法也可以给线程起名字
线程调度及获取和设置线程优先级
线程的执行
假如我们的计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,
线程只有得到 CPU时间片,也就是使用权,才可以执行指令。那么Java是如何对线程进行调用的呢?
线程有两种调度模型:
分时调度模型 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
抢占式调度模型 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,
优先级高的线程获取的 CPU 时间片相对多一些。
如何设置和获取线程优先级
public final int getPriority() //获取线程的优先级
public final void setPriority(int newPriority)//设置线程的优先级
线程控制之休眠线程
sleep(long millis) 线程休眠
sleep(long millis) 线程休眠
加入线程: public final void join()
意思就是: 等待该线程执行完毕了以后,其他线程才能再次执行
注意事项: 在线程启动之后,在调用方法
四、 多线程程序实现的方式2
public class MyRunnable implements Runnable{
@Override
public void run() {
//需要线程执行
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
-----------------------------------------------------------
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread th = new Thread(myRunnable);
th.start();
new MyThread().start();
}
}
---------------------------------------------
五、 多线程程序实现的方式3
A:实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
B:执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。 FutureTask 是 Future 接口的实现类
实现步骤
1.创建一个类实现Callable 接口
2.创建一个FutureTask类将Callable接口的子类对象作为参数传进去
3.创建Thread类,将FutureTask对象作为参数传进去
4.开启线程
public class MyCallable implements Callable<Integer> {
//call方法就是线程要执行的方法
@Override
public Integer call() throws Exception {
System.out.println("线程执行了");
int sum=0;
for (int i = 1; i <= 100; i++) {
sum+=i;
}
return sum;
}
}
------------------------------------------------
public class MyTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程的方式3
MyCallable myCallable = new MyCallable();
FutureTask<Integer> task = new FutureTask<>(myCallable);
Thread thread = new Thread(task);
thread.start();
//线程执行完之后,可以获取结果
Integer integer = task.get();
System.out.println(integer);
}
}
八、 实现Runnable接口的方式卖电影票
案例演示:
public class MyRunnable implements Runnable{
static int piao = 100;
@Override
public void run() {
while (true) {
if (piao > 1) {
String name = Thread.currentThread().getName();
System.out.println(name + "正在出售" + (piao--) + "张票");
}
}
}
}
---------------------------------------------------------------------
public class MyTest {
public static void main(String[] args) {
//A:
//案例演示
//需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,
//请设计一个程序模拟该电影院售票。
MyRunnable myRunnable1 = new MyRunnable();
Thread th1 = new Thread(myRunnable1);
Thread th2 = new Thread(myRunnable1);
Thread th3 = new Thread(myRunnable1);
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
}
}
八、 同步代码块的方式解决线程安全问题
public class MyRunnable implements Runnable {
static int piao = 100;
static Object obj = new Object();
int i=1;
@Override
public void run() {
while (true) {
//我们在实际网上购票时,会有一些网络延迟,我们可以使用休眠来模拟一下
//剩余最后两张票
//th1 th2 th3
if(i%2==0){
//同步代码使用任意对象,作为锁
synchronized (MyRunnable.class) { //锁 ,其实就是一个任意对象,多个线程要共享一把锁
if (piao >= 1) {
try {
Thread.sleep(10);//模拟网络延迟 th1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + (piao--) + "张票");
}
}
}else{
cellPiao2();
}
i++;
//释放锁
}
}
---------------------------------
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable1 = new MyRunnable();
Thread th1 = new Thread(myRunnable1);
Thread th2 = new Thread(myRunnable1);
Thread th3 = new Thread(myRunnable1);
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
}
}
九、 死锁问题概述和使用
概述
如果出现了同步嵌套,就容易产生死锁问题
是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
同步代码块的嵌套案例
死锁: 两个或者两个以上的线程,在抢占CPU的执行权的时候,都处于等待状态
举例: 中国人和美国人一起吃饭
中国人使用的筷子
美国人使用的刀和叉
中国人获取到了美国人的刀
美国人获取到了中国人的一根筷子
案例演示:
注意事项: //同步代码块,用的锁对象,是任意锁对象
//同步方法用的锁对象是this
//静态同步方法用的锁对象是 字节码类型
public class MyRunnable implements Runnable {
static int piao = 100;
static Object obj = new Object();
int i=1;
@Override
public void run() {
while (true) {
//cellPiao();
cellPiao2();
}
}
//方法上加有一个synchronized关键字我们叫做同步方法
//同步方法使用的所对象不是任意对象,他用的锁是this
private synchronized void cellPiao() {
if (piao >= 1) {
try {
Thread.sleep(20);//模拟网络延迟 th1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + (piao--) + "张票");
}
}
//静态同步方法使用的锁对象,不是任意对象,他用的锁是,当前类的 字节码类型
private synchronized static void cellPiao2() {
if (piao >= 1) {
try {
Thread.sleep(20);//模拟网络延迟 th1
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + (piao--) + "张票");
}
}
}
------------------------------------------------
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable1 = new MyRunnable();
Thread th1 = new Thread(myRunnable1);
Thread th2 = new Thread(myRunnable1);
Thread th3 = new Thread(myRunnable1);
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
}
}