多线程编程实验

2023-05-16

(一)查看下列程序并运行,掌握如何通过扩展Thread类创建线程。
package case1;

public class MySimpleThread extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 8; j++) {
                System.out.print(getName() + "[" + j + "]  ");
            }
            System.out.println();
        }
        System.out.println("-----" + getName() + " ends-----");
    }

    public static void main(String[] args) {
        Thread thread1 = new MySimpleThread();
        thread1.setName("T1");
        Thread thread2 = new MySimpleThread();
        thread2.setName("T2");
        thread1.start();
        thread2.start();
        System.out.println("=====" + Thread.currentThread().getName() + " ends=====");
    }
}

说明:首先,启动一个线程应该调用start()方法,而不是直接调用run()方法,启动start()方法后,具体该线程何时执行,分配多长时间执行都交由操作系统去分配,而不是由程序员来控制。在线程执行过程中,可以调用Thread类的静态方法currentThread()来查看当前哪个线程正在执行。另外,从程序中我们可以看出来,Java程序的入口main()方法其实也是由java虚拟机启动的一个线程来调用的,其默认名字为main。我们多次运行该程序,会得到不同的运行结果,因为每次操作系统为不同线程分配的时间片是不固定的,因此多次运行程序可以看出多线程程序的特点。
在这里插入图片描述
写一个扩展Thread类创建线程的例子并运行。

package case1;

import java.util.Random;

// 通过继承Thread类来创建线程类
public class ThreadDemo extends Thread {
    // 重写run方法,run方法的方法体就是线程执行体
    public void run() {
        Random rand = new Random();
        for (int i = 0; i < 10; i++) {
            // 当线程类继承Thread类时,直接使用this即可获取当前线程
            // Thread对象的getName()返回当前该线程的名字
            // 因此可以直接调用getName()方法返回当前线程的名
            System.out.println(getName() + " " + rand.nextInt(10000));
        }
        System.out.println("====" + getName() + " ends====");
    }

    public static void main(String[] args) {
        Thread thread_1 = new ThreadDemo();
        thread_1.setName("T1");
        Thread thread_2 = new ThreadDemo();
        thread_2.setName("T2");
        thread_1.start();
        thread_2.start();
    }
}

在这里插入图片描述

(二)查看下列程序并运行,掌握如何通过Runnable接口创建线程。
package case2;

public class MySimpleRunnable implements Runnable {
	public void run(){
		for(int i=0; i<5; i++){
			for(int j=0; j<8; j++){
				System.out.print(Thread.currentThread().getName()+"["+j+"]  ");
			}
			System.out.println();
		}
		System.out.println("-----" + Thread.currentThread().getName() + " ends-----");
	}
	
	public static void main(String [] args){
		Thread T1 = new Thread(new MySimpleRunnable ());
		Thread T2 = new Thread(new MySimpleRunnable ());
		T1.start();
		T2.start();
		System.out.println("====="+Thread.currentThread().getName()+" ends=====");
	}
}

在这里插入图片描述
对比程序(一),程序(二)有什么不同?
相比程序(一),程序(二)创建线程的方法是:创建Thread类的对象将Runnable接口的子类对象作为参数传递给Thread类的构造函数。

对以上两种创建线程的方式做出总结。
(1) 创建线程的方式和具体步骤
①继承Thread类:
a.定义一个类继承Thread;
b.重写run方法;
c. 创建子类对象(创建线程对象);
d. 调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法
② 实现Runnable接口:
定义类实现Runnable接口;
覆盖接口中的run方法;
创建Thread类的对象;
将Runnable接口的子类对象作为参数传递给Thread类的构造函数;
调用Thread类的start方法开启线程。
(2) 优点和缺点
①采用继承Thread类方式:
a.优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
b.缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

②采用实现Runnable接口方式:
a.优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
b.缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
写一个通过Runnable接口创建线程的例子并运行。

package case2;

class MyThread implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+" "+Math.random()
            );
        }
        System.out.println("========" + Thread.currentThread().getName() + " ends=======");
    }
}

public class Test {
    public static void main(String[] args) {
        Thread a = new Thread(new MyThread());
        Thread b = new Thread(new MyThread());
        Thread c = new Thread(new MyThread());
        a.start();
        b.start();
        c.start();
    }
}

在这里插入图片描述

(三)下列是一个模拟车票预定的程序。
package case3;

class BookingClerk {
	int remainder = 10;
	synchronized void booking(int num){
		if(num <= remainder){
			System.out.println("预定"+num+"张票"); 
			try{
				Thread.sleep(1000);
				remainder = remainder - num;
			} catch(InterruptedException e){
				remainder = remainder - num;
			}
		} else {
			System.out.println("剩余票不足,无法接受预定");
		}
		System.out.println("还剩"+remainder+"张票");
	}
}

class BookingTest implements Runnable{
	BookingClerk bt;
	int num;
	BookingTest(BookingClerk bt, int num){
		this.bt = bt;
		this.num = num;
		new Thread(this).start();
	}
	
	public void run(){
		bt.booking(num);
	}
	
	public static void main(String [] args){
		BookingClerk bt = new BookingClerk();
		new BookingTest(bt, 7);
		new BookingTest(bt,5);
	}
}

运行此程序,发现有什么问题?
剩余票数为负数。
说明导致出现此问题的原因?
有些资源在同一时刻只被一个线程所利用。
修改上例程序,运用线程同步与互斥的相关知识,使其不会再出现之前的错误?
用synchronized关键字声明booking()方法为同步方法

synchronized void booking(int num)
(四)下列是模拟数据读写的程序。
package case4;

public class QueueOld {
    protected Object[] data;
    protected int writeIndex;
    protected int readIndex;
    protected int count;

    public QueueOld(int size) {
        data = new Object[size];
    }

    public void write(Object value) {
        data[writeIndex++] = value;
        System.out.println("write data is: " + value);
        writeIndex %= data.length;
        count += 1;
    }

    public void read() {
        Object value = data[readIndex++];
        System.out.println("read data is: " + value);
        readIndex %= data.length;
        count -= 1;
    }

    public static void main(String[] args) {
        QueueOld q = new QueueOld(5);
        new Writer(q);
        new Reader(q);
    }
}

class Writer implements Runnable {
    QueueOld queue;

    Writer(QueueOld target) {
        queue = target;
        new Thread(this).start();
    }

    public void run() {
        int i = 0;
        while (i < 100) {
            queue.write(new Integer(i));
            i++;
        }
    }
}

class Reader implements Runnable {
    QueueOld queue;

    Reader(QueueOld source) {
        queue = source;
        new Thread(this).start();
    }

    public void run() {
        int i = 0;
        while (i < 100) {
            queue.read();
            i++;
        }
    }
}

运行此程序,发现有什么问题?
读写数据时发生混乱的情况。
修改上例程序,运用线程同步与互斥的相关知识,使其不会再出现之前的错误?

package case4;

public class Queue {

    protected Object[] data;
    protected int writeIndex;
    protected int readIndex;
    protected int count;
a
    public Queue(int size) {
        data = new Object[size];
    }

    public synchronized void write(Object value) {
        while (count >= data.length) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        data[writeIndex++] = value;
        System.out.println("write data is: " + value);
        writeIndex %= data.length;
        count += 1;
        notify();
    }

    public synchronized void read() {
        while (count <= 0) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        Object value = data[readIndex++];
        System.out.println("read data is: " + value);
        readIndex %= data.length;
        count -= 1;
        notify();
    }

    public static void main(String[] args) {
        Queue q = new Queue(5);
        new Writer(q);
        new Reader(q);
    }

}

class Writer implements Runnable {
    Queue queue;

    Writer(Queue target) {
        queue = target;
        new Thread(this).start();
    }

    public void run() {
        int i = 0;
        while (i < 100) {
            queue.write(new Integer(i));
            i++;
        }
    }
}

class Reader implements Runnable {
    Queue queue;

    Reader(Queue source) {
        queue = source;
        new Thread(this).start();
    }

    public void run() {
        int i = 0;
        while (i < 100) {
            queue.read();
            i++;
        }
    }
}

在这里插入图片描述

(五)使用10个线程,第一个线程完成从1加到10,第2个线程从11加到20,…,第10个线程从91加到100,最后把10个线程结果相加。输出最后的结果。
package case5;

// 使用线程数组,实例化对象为Thread类型对象,需建立Thread类的对象
class Addition extends Thread {
    private int currNum;
    private static int sum;

    public Addition(int currNum) {
        this.currNum = currNum;
    }

    public static synchronized void add(int num) {
        sum = sum + num;
    }

    public void run() {
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            sum = sum + currNum + i;
        }
        add(sum);
    }

    // 10个线程结果相加
    public int getSum() {
        return sum;
    }
}

public class Test {
    public static void main(String[] a) {
        // 创建线程数组
        Thread[] threadList = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadList[i] = new Addition(10 * i + 1);
            threadList[i].start();
        }
        Addition a1 = new Addition(0);
        System.out.println("Sum is : " + a1.getSum());
    }
}
(六)线程和进程的区别是什么?

①进程:一个在内存中运行的应用程序;
②线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行;
③区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。

(七)创建线程的方式有哪两种?如何启动一个线程?

①创建线程的两种方式:继承Thread类和实现Runnable接口; ②启动一个线程的方法:.star()方法和run()方法。

(八)线程有哪几种状态?状态之间是如何转换的?

①线程的五种状态:新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)、死亡状态(Dead);
②状态之间的转换方式如下图:
在这里插入图片描述

(九)什么叫“临界资源”?什么叫“临界区”?什么叫“同步方法”?

①是一次仅允许一个进程使用的共享资源;
②每个进程中访问临界资源的那段代码称为临界区;
③有synchronized关键字修饰的方法叫做同步方法。

(十)Java中的同步方法是如何处理临界区的互斥问题的?

使用synchronized来给共享区域加锁,确保共享资源安全。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多线程编程实验 的相关文章

  • STM32-串口通信(串口的接收和发送)

    文章目录 STM32的串口通信一 STM32里的串口通信二 串口的发送和接收串口发送串口接收 三 串口在STM32中的配置四 串口接收的两种实现方式1 需要更改的地方2 查询RXNE标志位3 使用中断 总结 STM32的串口通信 本文在于记
  • quick sort(c++)以及k选取

    include lt iostream gt include lt vector gt using rank 61 int using namespace std int dash 61 0 int swap vector lt int g
  • STLINK CONNECTION ERROR 问题的解决

    打开STLINK UTILITY 连接芯片也连接不上 在settings里面 选择这个连接模式 xff0c 按下芯片复位键的同时 xff0c 点击连接 st link的灯闪烁红蓝相间的光表示连接成功 松开芯片reset xff0c 既连接成
  • 解决ros2安装出现的问题

    Cannot locate rosdep definition for python3 pytest 解决方法是输入弹幕命令 然后输入安装功能依赖的命令 如果有占用进程问题 xff0c 就重启 http t csdn cn WwqJa
  • conda activate 出错

    问题及解决办法 1 使用conda activate出错 在cmd中使用 conda bat activate 进入环境后在进行操作 2 conda install出错 xff0c 使用pip install 3 在cmd 中使用tenso
  • 树莓派4b 安装ubuntu20.04server和图形化界面遇到的问题

    树莓派安装图形界面参考教程 树莓派4b安装Ubuntu 18 04系统及图形桌面 树莓派4B安装 ubuntu20 04 amp VNC远程桌面 amp 安装ROS noetic 树莓派4b安装Ubuntu和ROS的完整爬坑记录 2021年
  • 【STM32】串口接收任意字符串

    目录 前言cube配置usart h xff1a usart cmain xff1a 效果 前言 之前写了一篇STM32hal库串口中断接收任意字符 实际上是不完美的 xff0c 他接收到换行符就完蛋了 花了点时间深入研究了一下hal库的串
  • 使用封装的axios发送请求

    使用封装的axios发送请求 1 src api api js 定义请求路由方法 span class token function import span URLS from span class token string 39 conf
  • STM32串口驱动

    首先了解串口通信的一些基本原理 xff1a 串口通信 xff1a 串口通信是指数据通过一条数据线 xff08 或者两条差分线 xff09 一位接着一位的传输出去 串口通信的优点是占用硬件资源少 xff0c 且传输距离较远 xff0c 缺点是
  • IIC 驱动OLED

    IIC总线可以驱动很多器件 xff0c 比较常见的有OLED EEPROM存储器 xff08 AT24C02 xff09 温度传感器 xff08 LM75A xff09 温湿度传感器 xff08 DHT11 xff09 等 有关IIC总线协
  • Stm32-使用TB6612驱动电机及编码器测速

    这里写目录标题 起因一 电机及编码器的参数二 硬件三 接线四 驱动电机1 TB6612电机驱动2 定时器的PWM模式驱动电机 五 编码器测速1 定时器的编码器接口模式2 定时器编码器模式测速的原理3 编码器模式的配置4 编码器模式相关代码5
  • CAN总线协议入门基础原理

    CAN 是 Controller Area Network 的缩写 xff08 以下称为 CAN xff09 xff0c 是 ISO 1 国际标准化的串行通信协议 CAN 通过 ISO11898 及 ISO11519 进行了标准化 xff0
  • SPI总线协议基本原理及相关配置

    单片机应用中 xff0c 最常用的通信协议主要有三个 xff0c 即USART IIC和SPI 关于前两个的介绍在之前文章学习过 xff0c 这次介绍一下第三个通信协议 SPI SPI Serial Peripheral Interface
  • 利用定时器的输出比较功能产生PWM驱动舵机

    一 定时器基本原理 首先我们来看一下ST官方给出的关于定时器的相关介绍 xff1a xff08 以STM32F103C8T6为例 xff09 STM32F103C8T6 含有 4 个 16 位定时器 xff0c 分别是一个高级定时器 TIM
  • ST-LINK固件升级

    关于st link固件升级注意的问题 在下载调试的过程中 xff0c 程序可能由于st link版本过旧而提示 command not supported 的错误 xff0c 这就要求我们升级st link固件才可以正常下载 但是在升级的过
  • 关于英伟达jetson nano的搭配双目摄像头跑ORB_SLAM2

    1 安装系统 按照商家给的资料安装 xff0c 将Ubuntu18 04LTS镜像拷贝到tf卡中 xff0c 插上jetson nano就可以安装了 2 系统设置 进入系统我先把系统语言设置为中文 xff0c 在右上角的设置中找到系统设置中
  • 双目摄像头(CSI-IMX219)的标定

    1 介绍 网上关于这类标定有挺多教程的 xff0c 但由于这个摄像头的特殊性 xff0c 所以不可能完全安装教程来走 目前来说有3种标定方法 xff1a ROS操作系统来标定 matlab标定 opencv标定 这三种方法我先试了用ROS来
  • 小学生学AD16(入门级别,看这篇就够了)

    1 软件安装 xff1a AD16的安装我就不多介绍了 xff0c csdn一搜一大把 要学一个软件 xff0c 那么软件安装是必经之路 xff0c 不要认为软件安装不重要 xff08 如果你的安装完之后桌面没快捷方式 xff0c 那么可以
  • Arduino串口绘图器双通道绘制

    Serial print val Serial print 34 34 Serial println muBiao 其实只用在两个变量之间加个 xff0c 就行了 参考网址 https www norwegiancreations com
  • 关于神舟笔记本TX8连副屏经常蓝屏的问题

    大概率是3060显卡驱动的问题 xff0c 可以试试重新安装显卡驱动 若还是不行就换个接口 xff0c 不要用hdim的接口 xff0c 那个是直接连3060的 换剩下两个的minidp接口其中一个 xff0c 第一个不要接 xff0c 那

随机推荐

  • 51单片机入门(小学生都能学会)

    序 xff1a 时隔一年 xff0c 我终于从二年级到三年级了 xff01 由于小学三年级这学期要学单片机 xff0c 故写下这篇笔记留下些什么 由于自己也是新手 xff0c 欢迎各位指出本文的各种错误 1 什么是51单片机 为什么要说这个
  • 解决使用WinScp连接Ubantu系统失败的问题---SSH无法连接

    起因 为了互通Linux系统和Windows系统的文件 xff0c 以更好的实现文件管理和资源共享 所以在查阅资料后 xff0c 使用WinScp xff0c WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端 它的
  • 小学生51系列之基础知识

    1 单片机的基本结构 说到基本结构 xff0c 就是指51单片机的硬件组成 51单片机由中央处理器CPU 储存器 定时器 I O端口 组成 其中储存器包含数据储存器 xff08 RAM xff09 和程序储存器 xff08 ROM xff0
  • ros 接入Livox Mid-70

    最近在研究3d避障激光 大疆Livox mid 70 xff0c 记录下接入过程 环境信息 xff1a Ubuntu 18 04 ros melodic 1 livox view 点云可视化 xff08 1 xff09 根据livox mi
  • ROS+opencv实践-二维码识别

    一 安装二维码识别的功能包 sudo apt span class token operator span get install ros span class token operator span melodic span class
  • C语言简单链表详细步骤详解

    43 链表 gt 小阿豪带你写链表 xff01 xff01 xff01 xff01 进入正文 span class token number 1 span 首先 xff0c 先想好自己要创建的链表格式以及最后的的显示界面 xff01 xff
  • 滚球控制系统详解 —— (附核心代码)

    最近练习了17年的国赛题 滚球控制系统 这里展示一下画圆 xff1a 观看完整视频点这里 接下来 xff0c 我来分享一下从搭整体结构到调试完的过程 这是我搭完的整体结构 xff08 缩小版 xff09 不管什么题 xff0c 结构部分还是
  • 【Linux网络编程】你了解TIME_WAIT状态吗?

    在Linux网络编程中 xff0c 我相信大多数人觉得最难理解的就是TCP中的TIME WAIT状态了吧 xff0c 那么TIME WAIT的概念到底是什么 xff0c 有几个类型呢 xff0c 以及在面试中经常会问到的TIME WAIT状
  • 【图解】八幅图带你轻松掌握八大排序(上):冒泡排序、选择排序、插入排序、快速排序

    在算法中 xff0c 八大排序算是最简单的也是重中之重 xff0c 所以掌握好八大排序的思想是非常重要的 xff0c 很多人学排序的时候会觉得似懂非懂 xff0c 本篇文章作者耗时两小时绘制了八大排序的详细图解 xff0c 让大家快速理解八
  • 最详细整理STL之vector基础

    前言 xff1a Vector是一种可以存储任意类型的动态数组 xff0c 属于序列式容器 xff0c 可以用sort对其进行排序 xff0c 底层数据结构是数组 xff0c 可以随机访问元素 Vectors 包含着一系列连续存储的元素 其
  • STL之vector扩容机制

    前言 大家好 xff0c 我是萝卜 上期结尾说到vector的push back操作一般情况下时间复杂度为O 1 xff0c 是否存在特殊情况 那么本期就讲讲vector在容器空间不足时进行push back操作会发生什么 vector作为
  • 求职嵌入式软件开发linux kernel/BSP leader/工程师职位

    个人工作说明 xff1a 目前从事linux系统网络设备的开发工作 xff0c 负责bootloader linux kernel文件系统 xff0c driver移植 xff0c 以及开源app移植 主要技能和过去的经验 xff1a 1
  • 【2023最新】计算机网络面试题【收藏持续更新】

    你好 xff0c 我是萝卜 xff0c 我会在本篇文章持续更新关于计算机网络的面试题 最新内容更新日期 xff1a 2023 04 11 基础 说一下计算机网络体系结构 网络体系结构一般有三种 xff1a ISO七层模型 xff0c TCP
  • UDP协议详解

    概述 xff1a UDP只在IP的数据报服务之上增加了两个最基本的服务 xff1a 复用和分用以及差错检测 UDP不保证可靠交付 xff0c 但是不意味着应用对数据的要求是不可靠的 xff0c 只是所有维护可靠性的工作可由用户在应用层完成
  • TCP传输可靠性保证机制之重传机制

    TCP重传机制 tcp重传机制包括超时重传 快速重传 带选择确认的重传 SACK 重复SACK 四种 超时重传 xff1a 超时重传是tcp协议保证数据可靠性的一个重要机制 原理是在发送某一个数据以后开启一个计时器 xff0c 在一定时间内
  • VSCode:终端控制台常用指令

    常用的指令 以下是一些在 Visual Studio Code 终端控制台中常用的指令 xff1a 1 清除终端 xff1a clear 2 列出当前目录中的文件和文件夹 xff1a ls 3 切换到指定目录 xff1a xff1a cd
  • Ubuntu18.04安装ROS时rosdep update报错解决办法

    在安装ros进行rosdep update时经常会报错 xff0c 有时候可以通过换网解决 xff0c 但从我安装那么多次的经验来看 xff0c 仅有一次换手机热点后更新成功了 xff0c 其他都是失败 xff0c 成功率太低 从网上搜到了
  • 【STM32】STM32F103C8T6串口通信,实现3个串口收发数据

    串口通信 xff08 Serial Communications xff09 实现单片机与电脑或者其它外设进行通信 xff0c 通信时只需两根线 xff08 TX xff0c RX xff09 就可以实现数据传输 STM32f103有三个串
  • C语言学习笔记——(2)数组

    数组 1 什么是是数组2 数组的定义2 1数组的表达2 2数组的含义2 3数组的大小 xff1a 3 字符数组4 字符串操作5 二维数组 1 什么是是数组 数组是指有序的元素序列 如果将有限个类型相同的变量的集合命名 xff0c 那么这个名
  • 多线程编程实验

    xff08 一 xff09 查看下列程序并运行 xff0c 掌握如何通过扩展Thread类创建线程 span class token keyword package span span class token namespace case1