Java后端开发45--多线程(一)

请添加图片描述
(以下内容全部来自上述课程)
在这里插入图片描述

多线程

线程(功能):线程是操作系统能够进行运算调度的最小单元。它被包含在进程之中,是进程中的实际运作单位。
进程(软件):进程是程序的基本执行实体。
线程的简单理解:应用软件中互相独立,可以同时运行的功能。

有了多线程,我们就可以让程序同时做多件事情
作用:提高效率
应用场景:只要你想让多个事情同时运行就需要用到多线程

1. 并发和并行

并发:在同一时刻,有多个指令在单个CPU上交替执行。
并行:在同一时刻,有多个指令在多个CPU上同时执行。

2. 实现方式

2.1 继承Thread类的方式进行实现

具体类可看API帮助文档

package com.itheima.a01threadcase1;
public class ThreadDemo {
	public static void main(String[] args) {
		/*
		*	多线程的第一种启动方式:	
		1.自己定义一个类继承Thread
		2.重写run方法
		*	3.创建子类的对象,并启动线程	
		* */
		
		MyThread t1 = new MyThread(); 
		MyThread t2 = new MyThread();
		t1.setName("线程1"); 
		t2.setName("线程2");
		t1.start(); 
		t2.start();
		
	}
}
package com.itheima.a01threadcase1;
public class MyThread extends Thread{
	@Override
	public void run() {
		//书写线程要执行代码
		for (int i = 0; i < 100; i++){
			System.out.println(getName()+ "HelloWorld");
		}
    }
}

2.2 实现Runnable接口的方式进行实现

package com.itheima.a02threadcase2;
public class ThreadDemo {
	public static void main(String[] args){
		/*
		* 多线程的第二种启动方式:
		*	1.自己定义一个类实现Runnable接口
		*	2.重写里面的run方法
		*	3.创建自己的类的对象	
		*	4.创建一个Thread类的对象,并开启线程
		* */
		
		//创建MyRun的对象
		//表示多线程要执行的任务 
		MyRun mr = new MyRun();
		//创建线程对象
		Thread t1 = new Thread(mr); 
		Thread t2 = new Thread(mr);
		//给线程设置名字
		t1.setName("线程1"); 
		t2.setName("线程2");
		
		//开启线程 
		t1.start(); 
		t2.start();
		}
}
package com.itheima.a02threadcase2;
public class MyRun implements Runnable{
	@Override
	public void run() {
		//书写线程要执行的代码
		for (int i = 0; i< 100;i++){
			//获取到当前线程的对象
			/*Thread t = Thread.currentThread();
			System.out.println(t.getName() + "HelloWorld!");*/
			System.out.println(Thread.currentThread().getName() + "HelloWorld")
			}
	}
}

2.3 利用Callable接口和Future接口方式实现

特点:可以获取多线程运行的结果

package com.itheima.a03threadcase3;
public class ThreadDemo{
	public static void main(String[] args){
	/*

		多线程的第三种实现方式:
		特点:可以获取到多线程运行的结果
		*	1.创建一个类MyCallable实现Callable接口
		*	2.重写call (是有返回值的,表示多线程运行的结果)
		*	3.创建MyCallable的对象(表示多线程要执行的任务)	
		*	4.创建FutureTask的对象(作用管理多线程运行的结果)	
		*	5.创建Thread类的对象,并启动(表示线程)	
		* */
		//创建MyCallable的对象(表示多线程要执行的任务) 
		MyCallable mc = new MyCallable();
		//创建FutureTask的对象(作用管理多线程运行的结果) 
		FutureTask<Integer>ft = new FutureTask<>(mc);
		//创建线程的对象
		Thread t1 = new Thread(ft);
		//启动线程 
		t1.start();
		//获取多线程运行的结果
		Integer result = ft.get(); 
		System.out.println(result);
	}
}
package com.itheima.a03threadcase3;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
	@override
	public Integer call() throws Exception {
		//求1~100之间的和 
		int sum = 0;
		for (int i = 1; i<= 100; i++) {
			sum = sum + i;
		}
		return sum;
	}
}

2.4 对比

请添加图片描述

3. 常见成员方法

请添加图片描述

3.1 常用方法的细节

在这里插入图片描述

  1. String getName() 返回此线程的名称
    void setName(String name) 设置线程的名字(构造方法也可以设置名字)
    细节:
  • 如果我们没有给线程设置名字,线程也是有默认的名字的
    格式:Thread-X(X序号,从0开始的)
  • 如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置
  1. static Thread currentThread() 获取当前线程的对象
    细节:
    当JVM虚拟机启动之后,会自动的启动多条线程其中有一条线程就叫做main线程
    他的作用就是去调用main方法,并执行里面的代码
    在以前,我们写的所有的代码,其实都是运行在main线程当中
  2. static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
    细节:
  • 哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
  • 方法的参数:就表示睡眠的时间,单位毫秒
    1 秒=1000毫秒
  • 当时间到了之后,线程会自动的醒来,继续执行下面的其他代码

3.2 线程的优先级

抢占式调度:随机性
范围:(1~10)
默认值是5
请添加图片描述

3.3 守护线程(应用)

请添加图片描述

3.4 礼让线程(了解)

请添加图片描述

3.5 插入线程(了解)

土豆(插入的)执行完了再执行main线程
请添加图片描述

4. 线程的生命周期

请添加图片描述

5. 线程的安全问题

可能出现的问题(以多线程卖票为例):

  1. 相同的票出现了多次
  2. 出现了超出范围的票

5.1 同步代码块

把操作共享数据的代码锁起来
请添加图片描述
特点:

  1. 锁默认打开,有一个线程进去了,锁自动关闭。
  2. 里面的代码全部执行完毕了,线程出来,锁自动打开
package com.itheima.a09threadsafe1;
public class MyThread extends Thread{
	//表示这个类所有的对象,都共享ticket数据 
	static int ticket = 0;//0 ~99
	//锁对象,一定要是唯一的
	static 0bject obj = new 0bject();
	
	@Override
	public void run() {
		while (true){
			//同步代码块
			synchronized (obj){
				if(ticket < 100){
					try {
						Thread.sleep( millis:10);
					} catch (InterruptedException e){
						e.printStackTrace();
					}
					ticket++;
					System.out.println(getName()+"正在卖第"+ ticket +"张票!!!");
				}else{
					break;
				}
			}
		}
	}
}

细节:

  1. 同步代码块不能在while的外面,否则相当于单线程执行。
  2. 锁对象,一定要是唯一的。

5.2 同步方法

就是把synchronized关键字加到方法上
格式:修饰符 synchronized 返回值类型 方法名(方法参数){…}
特点:

  1. 同步方法是锁住方法里面所有的代码
  2. 锁对象不能自己指定
  • 非静态:this
  • 静态:当前类的字节码文件对象

技巧:先写同步代码块,再抽取为同步方法

测试类:

package com.itheima.a10threadsafe2;
public class ThreadDemo {
	puNlic static void main(String[] args){
		/*
		需求:
		某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票利用同步方法完成技巧:同步代码块
		*/
		
		MyRunnable mr = new MyRunnable();
		Thread t1 = new Thread(mr); 
		Thread t2 = new Thread(mr); 
		Thread t3 = new Thread(mr);
		t1.setName("窗口1"); 
		t2.setName("窗口2"); 
		t3.setName("窗口3");
		t1.start(); 
		t2.start(); 
		t3.start();
	}
}

同步代码块:

package com.itheima.a10threadsafe2;
public class MyRunnable implements Runnable{
	int ticket = 0;
	
	@Override
	public void run({
		//1.循环
		while(true){
			//2.同步代码块(同步方法)
			synchronized (MyRunnable.class){
				//3.判断共享数据是否到了末尾,如果到了末尾 
				if(ticket == 100){
					break;
				}else{
					//4.判断共享数据是否到了末尾,如果没有到末尾 
					ticket++;
					System.out.println(Thread.currentThread().getName()+"在卖第"+ ticket + "张票!!!");
				}
			}
		}
	}
}

选中同步代码块–ctrl + alt + M:

@override
public void run() {
	//1.循环
	while (true) {
		//2.同步代码块(同步方法) 
		if (method()) break;
	}
}
//this
private synchronized boolean method(){
	//3.判断共享数据是否到了末尾,如果到了末尾 
	if (ticket == 100) {
		return true;
	} else {
		//4.判断共享数据是否到了末尾,如果没有到末尾 
		try{
			Thread.sleep(millis: 10);
		} catch (InterruptedException e){
			e.printStackTrace();
		}
		ticket++;
		System.out.println(Thread.currentThread().getName()+"在卖第"+ ticket +"张票!!!");
	}
	return false;
}
按需引入<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ant Design Vue 纯HTML项目示例</title> <!-- 引入Ant Design Vue的CSS --> <link rel="stylesheet" href="https://unpkg.com/ant-design-vue@3.2.21/dist/antd.css"> <!-- 引入Ant Design X Vue的CSS --> <link rel="stylesheet" href="https://unpkg.com/ant-design-x-vue@1.0.0/dist/antdx.css"> <!-- vue3引入 --> <script src="https://unpkg.com/dayjs/dayjs.min.js"></script> <script src="https://unpkg.com/dayjs/plugin/customParseFormat.js"></script> <script src="https://unpkg.com/dayjs/plugin/weekday.js"></script> <script src="https://unpkg.com/dayjs/plugin/localeData.js"></script> <script src="https://unpkg.com/dayjs/plugin/weekOfYear.js"></script> <script src="https://unpkg.com/dayjs/plugin/weekYear.js"></script> <script src="https://unpkg.com/dayjs/plugin/advancedFormat.js"></script> <script src="https://unpkg.com/dayjs/plugin/quarterOfYear.js"></script> <!-- vue3 --> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <!-- antdv --> <script src="https://cdn.jsdelivr.net/npm/ant-design-vue@4.2.6/dist/antd.min.js"></script> <!-- antdxv --> <script src="https://cdn.jsdelivr.net/npm/ant-design-x-vue@1.2.7/dist/index.umd.min.js"></script> </head> <body> <div id="app"></div> <script> const { createApp, ref, computed } = Vue; const { Button } = antd; const { Bubble, XProvider } = antdx; createApp({ template: ` <AXProvider :theme="{ algorithm: myThemeAlgorithm, }"> <div :style="{ padding: &#39;24px&#39;, backgroundColor: bgColor, }"> UMD <AXBubble content="hello bubble"></AXBubble> <AButton type="primary" @click="setLightTheme">Light</AButton> <AButton type="primary" @click="setDarkTheme">Dark</AButton> </div> </AXProvider> `, setup() { const { theme } = antd; const bgColor = ref("white"); const myThemeAlgorithm = ref(theme.defaultAlgorithm); const setLightTheme = () => { myThemeAlgorithm.value = theme.defaultAlgorithm; bgColor.value = "white"; }; const setDarkTheme = () => { myThemeAlgorithm.value = theme.darkAlgorithm; bgColor.value = "#141414"; }; return { myThemeAlgorithm, bgColor, setLightTheme, setDarkTheme }; } }) .use(XProvider) .use(Button) .use(Bubble) .mount("#app"); </script> <style> .container { max-width: 1200px; margin: 24px auto; padding: 0 16px; } .search-form { margin-bottom: 24px; padding: 16px; background-color: #f5f5f5; border-radius: 4px; } .user-table { margin-top: 16px; } .mb-6 { margin-bottom: 24px; } .mt-2 { margin-top: 8px; } </style> </body> </html>
07-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值