Java复习-多线程编程

news2024/12/22 23:43:48

多线程编程

解决并发访问的问题。

一. 继承 Thread 类实现多线程

1. 继承实现

  1. 继承thread类
    class MyThread extends Thread{}
  2. 覆写run主方法
    多线程要执行的功能都应该在 run() 方法中定义。
class MyThread extends Thread { // 线程的主体类
	private String title;
	public MyThread(String title) {
		this.title = title;
	}
	@Override
	public void run() { // 线程的主体方法
		// TODO Auto-generated method stub
		super.run();
		for(int x = 0; x < 10; x++) {
			System.out.println(this.title + "运行,x = " + x);
		}
	}
}
public class ThreadDemo {

}
  1. 主程序类之中执行 start() 方法
public class ThreadDemo {
	public static void main(String[] args) {
		new MyThread("线程A").start();
		new MyThread("线程B").start();
		new MyThread("线程C").start();
	}
}

2. 源码分析 start() 方法

start() 方法实际上执行的是 run() 方法中的内容,而通过观察 Thread类 源码中的start() 方法的源码,我们发现其中调用了如下的一个方法:
private native void start0(); // 只定义了方法名称,但是没有实现
其中,native 指的是 JNI(Java Native Interface)技术,利用这项技术可以使用操作系统提供的一些底层函数进行一些特殊的处理。
而在 Thread 类中的 start0() 方法就表示需要将此方法的实现依赖于不同的操作系统来实现,即其具体实现细节由java虚拟机(JVM)给出。
在这里插入图片描述

二. 基于 Runnable 接口实现多线程

1. 原因

继承Thread会有单继承的局限,而使用“基于 Runnable 接口实现多线程”可以克服该局限。

2. 接口源码定义

Runnable 中只有一个 run() 方法,因此是函数式接口,可通过Lambda表达式调用。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

3. 接口实现

3.1 正常实现

  1. 实现 Runnable 接口
    class MyThread implements Runnable{}
  2. 覆写 run() 方法
class MyThread implements Runnable { // 线程的主体类
	private String title;
	public MyThread(String title) {
		this.title = title;
	}
	@Override
	public void run() { // 线程的主体方法
		for(int x = 0; x < 10; x++) {
			System.out.println(this.title + "运行,x = " + x);
		}
	}
}
  1. 作为Thread的参数,借用 start() 方法
    由于 Runnable 接口中并没有start() 方法,因此对于多线程的启动仍然需要使用 Thread 类 针对于 Runnable 的构造方法。
// 源码中 Thread 关于 Runnable 的构造方法
public Thread(Runnable target) {
    this(null, target, "Thread-" + nextThreadNum(), 0);
}

主程序类中的代码为:

public class ThreadDemo {
	public static void main(String[] args) {
		Thread thA = new Thread(new MyThread("线程A"));
		Thread thB = new Thread(new MyThread("线程B"));
		Thread thC = new Thread(new MyThread("线程C"));
		
		thA.start();
		thB.start();
		thC.start();
	}
}

3.2 利用Lambda实现多进程定义

public class ThreadDemo {
	public static void main(String[] args) {
		for (int x = 0; x < 3; x++) {
			String title = "线程对象:" + x ;
			new Thread(()->{
				for (int y = 0; y < 10; y++) {
					System.out.println(title + "运行,y = " + y);
				}
			}).start();
		}
		
	}
}

总结: 以后开发之中对于多线程的实现,优先考虑 Runnable 接口实现,并且永恒都是通过Thread 类对象启动多线程。

三. Thread 和 Runnable 关系

1. 隐含的代理设计模式

在这里插入图片描述
多线程的设计之中,使用了代理设计模式的结构,用户自定义的线程主体只是负责项目核心功能的实现,而所有的辅助实现全部交由 Thread 类来处理。
在进行 Thread 启动多线程的时候调用的是 start()方法,而后找到的是 run() 方法

2. 资源并发访问

多线程开发的本质就是实现多个线程可以进行同一资源的抢占。Thread描述线程(实际项目中的用户),Runnable描述资源。
在这里插入图片描述
范例:利用卖票程序实现多个线程的资源并发访问

class MyThread implements Runnable { // 线程的主体类
	private int ticket = 5;

	@Override
	public void run() { // 线程的主体方法
		for(int x = 0; x < 10; x++) {
			if (this.ticket > 0)
				System.out.println("卖票,ticket = " + this.ticket --);
		}
	}
}
public class ThreadDemo {
	public static void main(String[] args) {
		MyThread mt = new MyThread();
		new Thread(mt).start(); //第一个线程启动
		new Thread(mt).start(); //第二个线程启动,这并不是同一个线程,而是同一个资源
		new Thread(mt).start(); //第三个线程启动,通过 new 实例化了三个线程,三个线程传入的Runnable都是mt
		
	}
}

在这里插入图片描述

四. Callable 接口实现多线程

Runnable 有一个缺点:当线程结束之后无法获得一个返回值,因此使用可返回值的Callable 接口。

1. 接口源码定义

  • Callable 也是函数式接口,可通过Lambda表达式调用。
  • Callable 其中只有一个 call() 方法,返回一个泛型,此泛型的类型就是返回数据的类型,可以避免由于向下转型所带来的安全隐患。
@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

2. Callable 与 Thread 关系分析

在这里插入图片描述

3. 接口实现范例

使用Callable实现多线程处理

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyThread implements Callable <String>{ // 1. 实现 Callable 接口并指出返回值类型
    // 2. 覆写 call()方法
	@Override
	public String call() throws Exception {
		for (int x = 0; x < 10; x++) {
			System.out.println("线程执行 x = " + x);
		}
		return "线程执行完毕!";
	}
}
public class ThreadDemo {
	public static void main(String[] args) throws Exception{
        // 3. 实例化 FutureTask 类,将线程实现类作为参数传入
		FutureTask<String> task = new FutureTask<>(new MyThread());
        // 4. 借由 FutureTask 实例化对象实现 start() 方法
		new Thread(task).start();
        // 5. 使用 FutureTask 实例化对象中的 get() 方法获得线程返回值
		System.out.println("线程返回数据: " + task.get());
	}
}

4. 面试题: Runnable 与 Callable 的区别?

  • Runnable 是在JDK1.0 的时候提出的多线程的实现接口,而 Callable 是在JDK1.5 之后提出的;
  • java.lang.Runnable 接口之中只提供有一个 run() 方法,并且没有返回值;
  • java.util.concurrent.Callable 接口提供有 call() 方法,可以有返回值。

五. 多线程运行状态

  1. 线程启动用的是 start() ,但此时对应的是“就绪态”;
  2. 当线程处于“运行态”时,会执行 run() 方法。
  3. run() 方法执行结束后,线程进入“结束态”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1004823.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows上Qt配置OpenCV(最简单版本无需自己编译-避坑必看)

文章目录 Windows上Qt配置OpenCV(最简单版本无需自己编译-避坑必看)1 前言2 软件安装2.1 安装qt2.2 安装OpenCV(分为vc版和mingw版)2.2.1 配置环境变量 3 Qt配置OpenCV3.1 创建一个项目(注意选择的是MinGW编译器还是MSVC编译器)msvc:mingw: 4 简单快捷添加OpenCV库的方法5 简单…

人类文明之光,历史上最伟大的10位程序员

21世纪&#xff0c;被称作计算机的时代&#xff0c;程序员是其中不可或缺的组成部分。不夸张的说&#xff0c;他们贡献改变了我们人类的整个文明进程。今天我们就来看看人类历史上最伟大的10位程序员。 丹尼斯里奇&#xff08;Dennis Ritchie&#xff09;&#xff1a;C语言之父…

驱动开发--自动创建节点udev机制的实现过程分析

一&#xff0c;创建设备文件的机制 1&#xff0c;mknod&#xff1a;手动创建设备节点 2&#xff0c;devfs&#xff1a;创建设备节点的逻辑在内核空间&#xff0c;2.5版本后淘汰 3&#xff0c;udev&#xff1a;自动创建设备节点的机制&#xff0c;逻辑在用户空间&#xff0c;…

Linux编辑器-vim使用

文章目录 前言一、vim编辑器1、vim的基本概念2、vim的基本操作2.1 命令模式切换至插入模式2.2 插入模式切换至命令模式2.3 命令模式切换至底行模式 3、vim命令模式命令集3.1 移动光标3.2 删除文字3.3 复制与粘贴3.4 替换3.5 撤销上一次操作3.6 更改3.7 跳至指定的行 4、vim末行…

相关性分析-Pearson, Spearman, Kendall 三大相关系数+绘制热力图

相关性分析 1、Pearson 相关系数(连续变量)Pearson代码2、Spearman 秩相关系数(连续变量)Spearman代码3、Kendall 相关系数 (有序分类变量)Kendall代码Pearson, Spearman, Kendall 三类相关系数是统计学上的三大重要相关系数,表示两个变量之间变化的趋势方向和趋势程度。…

将Windows本地的数据集上传到Linux服务器

一、用MobaXterm软件 软件界面如下&#xff1a; 在左侧边栏中找到存放数据集的位置&#xff0c;点击上传按钮&#xff08;这里只能上传单个文件&#xff09;&#xff0c;就可以完成上传了。 具了解上传速度为1M/s-22M/s. 其他方法待尝试&#xff0c;未完待续。。。。 点赞…

C语言实现三子棋游戏(详解)

目录 引言&#xff1a; 1.游戏规则&#xff1a; 2.实现步骤&#xff1a; 2.1实现菜单&#xff1a; 2.2创建棋盘并初始化&#xff1a; 2.3绘制棋盘&#xff1a; 2.4玩家落子&#xff1a; 2.5电脑落子&#xff1a; 2.6判断胜负&#xff1a; 3.源码&#xff1a; 结语&…

STLINK-V3 STDC14座转2.54mm排针转接板Kicad工程

简介 这是一个 STLINK-V3 STDC14座转2.54mm排针转接板Kicad工程 。STDC14座实际工作中不太方便&#xff0c;所以搞了这个转接板。另外转接版上提供了可选的电源输出功能。 An adapter board for STLINK-V3. It change the STDC14 to 2.54mm pin header.It also provides 5V an…

哪里可以了解轻量的工作流引擎?

如果想要实现高效率的办公&#xff0c;可以使用轻量的工作流引擎低代码技术平台。随着工作量日益繁重起来&#xff0c;传统的办公制作方式已经无法满足现实需要的&#xff0c;采用轻量级的表格制作工具&#xff0c;就能在无形中缓解办公压力&#xff0c;创造更高效、灵活、优质…

phpcmsV9.6.0sql注入漏洞分析

目录 前言 环境准备 漏洞点 看一看parse_str函数 看一看sys_auth函数 看一看get_one函数 全局搜索sys_auth($a_k, ENCODE) 查看哪里调用了 set_cookie 查看safe_replace函数 判断登录绕过 index的业务 加载modules/wap/index.php 加载modules/attachment/attachme…

小节6:Python字典dict

1、字典的键必须时不可变数据类型&#xff0c;所以列表list不能作为键key&#xff0c;那怎么办呢&#xff1f;Python为我们准备了一个很像列表&#xff0c;却又不可变的数据类型——元组tuple&#xff0c;通常用元组tuple来作为键。比如&#xff1a; contact_dict {("张…

简单的洗牌算法(Java)

目录 一、问题二、创建一个Poker类三、完成游戏内容四、测试五、总结 简单的洗牌算法是对ArrayList的具体使用 一、问题 我们需要一副完整的扑克牌&#xff0c;除去大小王一共52张牌&#xff0c;参与游戏的玩家共3名&#xff0c;在洗牌后分发每名玩家5张扑克牌。 二、创建一…

Prometheus+Grafana可视化监控【MySQL状态】

文章目录 一、Prometheus监控MySQL二、Grafana添加MySQL监控模板 PrometheusGrafana部署请参考上篇文章: PrometheusGrafana部署: 一、Prometheus监控MySQL 1、创建MySQL监控用户 mysql> create user "prometheus""%" identified by NTQ34tg*19VF; m…

Java——比较器

引入的背景 我们知道基本数据类型的数据&#xff08;除boolean类型外&#xff09;需要比较大小的话&#xff0c;直接使用比较运算符即可&#xff0c;但是引用数据类型是不能直接使用比较运算符来比较大小的。那么&#xff0c;如何解决这个问题呢&#xff1f; 在Java中经常会涉…

[杂谈]-从硬件角度理解二进制数

从硬件角度理解二进制数 文章目录 从硬件角度理解二进制数1、概述2、模拟电路3、数字电路4、逻辑电平5、TTL 器件的电压水平6、总结 1、概述 二进制数以 2 为基数系统表示&#xff0c;该系统只有两 (2) 个不同的数值&#xff0c;即 0 和 1。就像最常见的那样&#xff0c;十进制…

C 风格文件输入/输出---无格式输入/输出---(std::fgetc,std::getc,std::fgets)

C 标准库的 C I/O 子集实现 C 风格流输入/输出操作。 <cstdio> 头文件提供通用文件支持并提供有窄和多字节字符输入/输出能力的函数&#xff0c;而 <cwchar>头文件提供有宽字符输入/输出能力的函数。 无格式输入/输出 从文件流获取字符 std::fgetc, std::getc …

Python引入模块——拿着别人的代码做自己的项目

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 本文专栏&#xff1a;Python专栏 专栏介绍&#xff1a;本专栏为免费专栏&#xff0c;并且会持续更新python基础知识&#xff0c;欢迎各位订阅关注。 目录 一、什么是Python模块 二、Python模块的作用 三、Py…

cmd 90 validate error!(达梦数据库日志报错)

达梦数据库报错 error-cmd 90 validate error! 环境介绍1 解决办法 环境介绍 某生产环境数据库启动后&#xff0c;dm_实例名_202309.log&#xff0c;偶尔报错cmd 90 validate error! 1 解决办法 接口用错了&#xff0c;消息非法&#xff0c;比如用 6 的 JDBC 连 7 或 7 的 …

C++QT 作业5

#include <iostream> #define PI 3 using namespace std; class Shape { protected:int zc;int mj; public:Shape(){}Shape(int z,int m):zc(z),mj(z){}~Shape(){}Shape(const Shape &other):zc(other.zc),mj(other.mj){cout<<"拷贝构造函数"<<…

【买入看涨期权策略(Long Call)】

买入看涨期权策略的收益主要来源于标的资产价格的上涨&#xff0c;是一种基础的期权策略&#xff0c;该策略最大的吸引力在于能给投资者提供很大程度的杠杆&#xff0c;投资者能够在标的资产价格上涨幅度较小的时候获得较大的盈利&#xff0c;并且其对应的风险值不会超过一个固…