第二十章 多线程总结

继承Thread 类
        Thread 类时 java.lang 包中的一个类,从类中实例化的对象代表线程,程序员启动一个新线程需要建立 Thread 实例。

         Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,start() 方法启动线程,该工作的功能被写在run() 方法中。
 

 
public class ThreadTest extends Thread{
	public void run() {
		for(int i=0;i<=10;i++) {
			System.out.print(i+" ");
		}
	}
 
	public static void main(String[] args) {
		ThreadTest t=new ThreadTest();
			t.start();
		}
}

实现 Runnable 接口
        线程都是通过扩展 Thread 类来创建的,如果程序员需要继承其他类(非Thread 类),而且还要是当前类实现多线程,那么可以通过  Runnable 接口来实现。

        实现 Runnable 接口的程序会创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联。

使用 Runnable 接口启动新的线程的步骤:

建立 Runnable 对象
使用参数为 Runnable 对象的构造方法创建 Thread 实例
调用 start() 方法启动线程
 

import java.awt.Container;
 
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
 
public class SwingAndThread extends JFrame{
	int count=0;//图标坐标
 
	public  SwingAndThread(){
		setBounds(300,200,250,100);//绝对定位窗体大小与位置
		Container cotainer=getContentPane();//主容器
		cotainer.setLayout(null);//使窗体不使用任何布局管理器
		
		Icon icon=new ImageIcon("1.gif");//图标对象
		JLabel jl=new JLabel(icon);//显示图标的标签
		jl.setBounds(10,10,200,50);//设置标签的位置与大小
		Thread t=new Thread() {//定义匿名线程对象
			public void run() {			
			while(true) {
				jl.setBounds(count,10,200,50);//将标签的横坐标用变量表示
				try {
					Thread.sleep(500);//使线程休眠500毫秒
				}catch(InterruptedException e) {
					e.printStackTrace();
				}
				count+=4;//使横坐标每次增加4
				if(count>=120) {
					count=10;//当图标到达标签的最右时,时其回到标签做左边
				}
			}
			
		}
	};
	t.start();//启动线程
	cotainer.add(jl);//将标签添加到容器中
	setVisible(true);//使窗体可见
	setDefaultCloseOperation(EXIT_ON_CLOSE);//设置窗体的关闭方式
	}
 
	public static void main(String[] args) {
		new SwingAndThread();
 
	}
}

线程的生命周期
        一旦线程进入可执行状态,它会在就绪与运行状态下转换,同时也有可能进入等待,休眠,赌塞或死亡状态。

要使线程处于就绪,有以下几种方法:

调用 sleep() 方法。
调用 wait() 方法。
等待输入/输出完成。
当线程处于就绪状态后,可以用以下几种方法使线程再次进入运行状态:

线程调用 notify() 方法。
线程调用 notifyAll() 方法。
线程调用 interrupt() 方法。
线程的休眠时间结束。
输入/输出结束。
操作线程的方法
 线程的休眠
        一种能控制线程行为的方法是调用 sleep() 方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。
 

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
 
import javax.swing.JFrame;
 
public class SleepMethodTest extends JFrame{
	private static Color[] color= {Color.BLACK,Color.BLUE,Color.CYAN,Color.GREEN,
		Color.RED,Color.ORANGE,Color.YELLOW,Color.PINK,Color.LIGHT_GRAY};//定义颜色数组
	private static final Random rand=new Random();//创建随机对象
	
	private static Color getC() {//获取随机颜色值的方法
		return color[rand.nextInt(color.length)];
	}
	
	public  SleepMethodTest(){
		Thread t=new Thread(new Runnable() {//创建匿名线程对象
			int x=30;//定义初始坐标
			int y=50;
			
			public void run() {
				while(true) {//无限循环
					try {
						Thread.sleep(100);//线程休眠0.1秒
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
					Graphics graphics=getGraphics();//获取组件绘图上下文对象
					graphics.setColor(getC());//设置绘图颜色
					graphics.drawLine(x, y,150, y++);//绘制直线并递增垂直坐标
					if(y>=180) {
						y=50;
					}
				}
			}
		});
		t.start();//启动线程
	}
 
	public static void main(String[] args) {
		init(new SleepMethodTest(),200,200);
 
	}
 
	public static void init(JFrame frame,int width,int height) {//初始化程序界面的方法
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(width, height);
		frame.setVisible(true);
	}
}

线程的加入

        当某个线程使用 join() 方法的加入一个线程时,另外一个线程会等待该线程执行完毕后再继续执行。

import java.awt.BorderLayout;
 
import javax.swing.JFrame;
import javax.swing.JProgressBar;
 
public class JoinTest extends JFrame{
	//定义两个线程
	private Thread threadA;
	private Thread threadB;
	//定义两个进度条组件
	private JProgressBar porgressBar=new JProgressBar();
	private JProgressBar porgressBar2=new JProgressBar();
	
 
	public static void main(String[] args) {
		JoinTest test=new JoinTest();
		test.setVisible(true);
 
	}
	public  JoinTest() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(200,200,200,100);
		getContentPane().add(porgressBar,BorderLayout.NORTH);//将进度条设置在窗体最北面
		getContentPane().add(porgressBar2,BorderLayout.SOUTH);//将进度条设置在窗体最南面
		//设置进度条显示数字字符
		porgressBar.setStringPainted(true);
		porgressBar2.setStringPainted(true);
		//使用匿名内部类形式初始化 Thread 实例
		threadA=new Thread(new Runnable() {
			int count=0;
			public void run() {//重写 run()方法
				while(true) {
					porgressBar.setValue(++count);//设置进度条的当前值
					try {
						Thread.sleep(100);//使线程A休眠100毫秒
						threadB.join();//使线程B调用join()方法
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		threadA.start();//启动线程A
		threadB=new Thread(new Runnable() {
			int count=0;
			public void run() {
				while(true) {
					porgressBar2.setValue(++count);//设置进度条的当前值
					try {
						Thread.sleep(100);//使线程休眠100毫秒
					}catch(InterruptedException e) {
						e.printStackTrace();
				}
					if(count==100)//当count变量增长为100时
						break;//跳出循环
				}
			}
		});
		threadB.start();//启动线程B
	}
 
}

线程的中断
        以往有时候会使用 stop() 方法停止线程,但当前版本的 JDK 早已废除了 stop() 方法,不建议使用 stop() 方法来停止一个线程的运行。现在提倡在 run() 方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。

        如果线程是因为使用了 sleep()或 wait()方法进入了就入就绪状态,可以使用 Thread()方法,同时程序破除了 InterruptedException 异常,在异常处理时结束了 while 循环。在项目中,经常在这里执行关闭数据连接和关闭 Socket 连接等操作。
 

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
 
public class InterruptedSwing extends JFrame{
	
	public InterruptedSwing (){
		JProgressBar porgressBar=new JProgressBar();//创建进度条
		getContentPane().add(porgressBar,BorderLayout.NORTH);//将进度条设置在窗体最北面
		JButton button=new JButton("停止");
		getContentPane().add(button,BorderLayout.SOUTH);//将进度条设置在窗体最北面
		//设置进度条显示数字字符
		porgressBar.setStringPainted(true);
		//使用匿名内部类形式初始化 Thread 实例
		Thread t=new Thread(new Runnable() {
			int count=0;
			
			public void run() {//重写 run()方法
				while(true) {
					porgressBar.setValue(++count);//设置进度条的当前值
					try {
						Thread.sleep(100);//使线程休眠100毫秒
					}catch(InterruptedException e) {//捕捉InterruptedException异常
						System.out.println("但前线程被中断");
						break;
					}
				}
			}
		});
		
		button.addActionListener(new ActionListener() {
 
			@Override
			public void actionPerformed(ActionEvent e) {
				t.interrupt();//中断线程
				
			}
			
		});
		t.start();//启动线程
	}
	
	public static void init(JFrame frame,int width,int height) {//初始化程序界面的方法
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(width, height);
		frame.setVisible(true);
	}
 
	public static void main(String[] args) {
		init(new InterruptedSwing(),100,100);
 
	}
}

线程的礼让
        Thread 类提供了一种礼让方法,使用 yied()方法表示,它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。

        yied()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用 yied()方法,因为操作系统会为线程自动分配 CPU 时间来执行。

线程的优先级
        每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的概率比较小,如垃圾回收线程的优先级就按照较低。

        线程的优先级可以使用 setPriority()方法调整,如果使用该方法设置的优先级不在 1~10,将产生IllegalArgumentException 异常。
 

 
public class PriorityTest implements Runnable{
	String name;
	
	public PriorityTest(String name) {
		this.name=name;
	}
	
	@Override
	public void run() {
		String tmp="";
		for(int i=0;i<5000;i++) {
			tmp+=i;//完成5万次字符串拼接
		}
		System.out.println(name+"线程完车任务");
	}
 
	public static void main(String[] args) {
		Thread a=new Thread(new PriorityTest("A"));
		a.setPriority(1);//A线程优先级最小
		Thread b=new Thread(new PriorityTest("B"));
		b.setPriority(3);
		Thread c=new Thread(new PriorityTest("C"));
		c.setPriority(7);
		Thread d=new Thread(new PriorityTest("D"));
		d.setPriority(10);//D线程优先级最大
		a.start();
		b.start();
		c.start();
		d.start();
	}
}

线程同步
        在单线程程序中,每次只能做一件事情,后面的事情需要等待前面的事情完成后才可以进行,但是如果使用多线程程序,就会发生两个线程抢占资源的问题,如两个人同事说话、两个人同时过同一个独木桥。所以,在多线程编程中需要防止这些资源访问的冲突。Java 提供了线程同步的机制来防止资源访问的冲突。
线程的安全
        在编写多线程时时,因该考虑到线程安全问题。实质上线程问题来源两个线程同时存取单一对象的数据。
运行结果:

线程同步机制
        所以解决多线程资源问题的方法基本上都是采用给定时间只允许一个线程访问共享资源的方法。这时就需要给共享源上一道锁。
1、同步块***
        Java中提供了同步机制,可以有效地防止资源冲突。同步机制使用 synchronized 关键字,使用该关键字包含的代码块称为同步块,也称临界区。
 

synchronized(Object){
}

2、同步方法

        同步方法就是在方法前面用 synchronized 关键字修饰的方法。

synchronized void f(){ } 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从意义中恢复,而不是从数据包中恢复

从书报&#xff0c;录放机&#xff0c;电视机到智能手机&#xff0c;vr 眼镜&#xff0c;所有学习的&#xff0c;娱乐的工具或玩具&#xff0c;几乎都以光声诉诸视听&#xff0c;一块屏幕和一个喇叭。 视觉和听觉对任何动物都是收发信息的核心&#xff0c;诉诸视觉和听觉的光和…

防火墙 iptables的使用

目录 什么是防火墙 原理 代理 防火墙的工具 4表5列 五链&#xff1a;控制流量的时机 四个表&#xff1a;如何控制流量 ​编辑 iptables 软件 格式 选项 查iptables 的规则 添加规则 A I 删除规则 清空规则 替换规则 R 修改默认规则&#xff08;默认是允…

springboot启动开启热部署

springboot启动开启热部署 手动方式 或者点idea上面的build->build project 自动方式 勾上Build project automatically 然后ctrl alt shift / 选择Registr 勾上就好了 新版idea可以在这里选 热部署范围设置 这是spring-boot-devtools起的作用&#xff0c;所以还…

ESD静电试验方法及标准

文章目录 概述静电放电抗扰标准静电放电实验室的型式试验静电放电试验配置静电放电试验方法 静电放电等级 参考静电放电发生器&#xff08;ESD&#xff09;试验方法及标准 概述 在低湿度环境下通过摩擦使人体充电的人体在与设备接触时可能会放电&#xff0c;静电放电的后果是&…

优化机器学习:解析数据归一化的重要性与应用

在机器学习中&#xff0c;数据归一化是一种数据预处理的技术&#xff0c;旨在将数据转换为相似的范围或标准化的分布。这样做的主要目的是消除不同特征之间的量纲差异或数值范围差异&#xff0c;以确保模型在训练时更稳定、更有效地学习特征之间的关系。 通常&#xff0c;机器…

Nginx热部署

快捷查看指令 ctrlf 进行搜索会直接定位到需要的知识点和命令讲解&#xff08;如有不正确的地方欢迎各位小伙伴在评论区提意见&#xff0c;小编会及时修改&#xff09; Nginx热部署 首先来讲一下为什么要进行热部署 nginx 支持热加载 热部署 &#xff0c;在不打断用户请求的情…

【海思SS528 | VDEC】MPP媒体处理软件V5.0 | 视频解码模块——学习笔记

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

vue3实现元素拖拽移动功能

效果图 实现拖拽移动 首先我们给需要实现功能的元素加一个draggable"true"让元素能够被拖拽 先来认识两个搭配draggable属性一起使用的事件——ondragstart和ondragend&#xff0c;它们的定义分别为&#xff1a; ①. ondragstart 事件在用户开始拖动元素或选择的文…

Spring-AOP与声明式事务

为什么要用AOP ①现有代码缺陷 针对带日志功能的实现类&#xff0c;我们发现有如下缺陷&#xff1a; 对核心业务功能有干扰&#xff0c;导致程序员在开发核心业务功能时分散了精力 附加功能分散在各个业务功能方法中&#xff0c;不利于统一维护 ②解决思路 解决这两个问题&…

使用STM32 HAL库驱动烟雾传感器的设计和优化

STM32 HAL库是STMicroelectronics提供的针对STM32系列微控制器的一套硬件抽象层库&#xff0c;可以简化开发过程并提供对各种外设的支持。本文将介绍如何使用STM32 HAL库来驱动烟雾传感器&#xff0c;并对传感器数据采集和处理进行优化。将包括HAL库的初始化、模拟信号采集、数…

el-select实现分屏效果

动态绑定class值 &#xff0c;多种判断 :class"type 8 ? home-stye-2 : type 24 ? home-stye-1 : home-stye-3" <div class"home-right-top"><div class"home-right-top-video"><el-row :gutter"20"><el-c…

微服务中配置Nacos热更新

启动Nacos startup.cmd -m standalone 在IDE中启动服务 打开nacos管理后台并选择配置列表 创建配置(这里以日期格式为例) 因为这里配置的是userservice的服务,所以在userservice服务的pom文件中引入依赖 配置一个bootstrap.yml文件 注意这里bootstrap文件中配置过的内容,在app…

linux下实现Qt程序实现开机自启动

1.原理 要想实现开机自启动&#xff0c;首先&#xff0c;QT是没有这种实现的&#xff0c;最好是靠电脑开机的启动目录启动软件&#xff0c;下面这个目录 /etc/xdg/autostart 这是操作系统中用于配置启动项的目录&#xff0c;该目录下存放着开机自启动的启动器(.desktop)文件…

Oracle--索引

文章目录 一、索引是什么?二、索引的原理三、索引的特征四、创建索引的方式五、怎么确认索引六、案列七、复合索引 一、索引是什么? 索引&#xff08;INDEX&#xff09;是数据库中用于提高查询效率的一种数据结构。它可以加速数据库表的数据查找、过滤和排序等操作。索引是一…

网络通信与TCP.IP协议

网络通信与TCP.IP协议 URI 用字符串标识某一互联网资源&#xff0c;而 URL 表示资源的地点&#xff08;互联网上所处的位置&#xff09;。可见 URL 是 URI 的子集 URL (Uniform Resource Locator)&#xff0c;统一资源定位符 &#xff0c;用于描述一个网络上的资源 DNS: &#…

C# 友元程序集

1.友元程序集 使用友元程序集可以将internal成员提供给其他的友元程序集访问。 程序集FriendTest1.dll [assembly:InternalsVisibleTo("FriendTest2")] namespace FriendTest1 {internal class Friend{string name;public string Name > name;public Friend(str…

Android修行手册 - 一篇文章从0到1搞一个Android Studio插件。

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

更改AndroidStudio模拟器位置

C盘何等的珍贵&#xff0c;可是好多工具&#xff0c;软件非得默认安装在C盘。。导致C盘越来越紧张。。 在日常使用过程中&#xff0c;安装任何软件都会将其安装到非系统盘下&#xff0c;Android模拟器也不能例外。保护好C盘也是日常一个良好的习惯。 Android AVD默认路径&…

数据挖掘 感知机

要使用感知机&#xff0c;我们首先要引入头文件&#xff0c;以下是感知机用的到头文件&#xff1a; import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import Perceptron from sklearn.model_selection import train_test_…

淘宝商品详情数据接口(店铺搬家、数据分析、代购商城、ERP选品、无货源铺货、品牌监控)

使用淘宝API接口需要以下步骤&#xff1a; 注册开发者账号&#xff1a;在淘宝开放平台&#xff08;https://o0b.cn/anzexi&#xff09;上注册一个开发者账号&#xff0c;并创建一个应用。 获取API密钥&#xff1a;在应用页面上获取API密钥&#xff0c;这是后续调用API接口的凭…