Java---线程详解

news2024/12/25 0:57:48

目录

一、线程的介绍

二、线程的使用

(1)多线程的实现

1:继承Thread类

2:实现Runnable接口

(2)设置和获取线程名称

1:继承Thread类

2:实现Runnable接口

(3)线程的优先级

(4)线程的控制

1:sleep方法

2:join方法

3:setDaemon方法

三、线程安全 


一、线程的介绍

线程是进程中的单个顺序控制流,是一条执行路径。说得简单点吧,比如说扫雷这个游戏,有一个线程是扫雷,有一个程序是计时,可这个计时并不是直接计时,它是等开始扫雷时才进行,其实我说的意思就是计时是一个程序,扫雷是一个程序,但他们是单独的程序,他们每一个程序其实就是一个线程。(个人理解的补充:在后面他执行的时候其实就是要拿到CPU的执行权,但一般电脑都是只有一个CPU吧,多个线程去抢,谁抢到了,就执行哪个线程)
单线程:一个进程中如果只有一条执行路径,就是单线程程序
多线程:一个进程中如果有多条执行路径,则称为多线程程序

 

二、线程的使用

(1)多线程的实现

多线程的实现方式有两种
1:继承Thread类
2:实现Runnable接口


1:继承Thread类(要重写Thread类中的run方法,并使用start方法启动线程)

//这是继承类
public class mythread extends Thread{
   public void run() {
	   for(int i=1;i<20;i++) {
		   System.out.println(i);
	   }
   }
}

//这是测试类
public class test {
   public static void main(String[] args) throws UnknownHostException {
	  mythread m1=new mythread();
	  mythread m2=new mythread();
	  m1.start();
	  m2.start();
   }
}

2:实现Runnable接口


public class mythread implements Runnable{
   public void run() {
	   for(int i=1;i<20;i++) {
		   System.out.println(i);
	   }
   }
}

//测试类

public class test {
   public static void main(String[] args) throws UnknownHostException {
	    mythread m=new mythread();
	    Thread m1=new Thread(m);
	    Thread m2=new Thread(m);
	    
	    m1.start();
	    m2.start();
   }
}

(2)设置和获取线程名称

1:继承Thread类


public class thread extends Thread{
   public void run() {
	   for(int i=0;i<10;i++) {
		   System.out.println(Thread.currentThread().getName()+":"+i);
	   }
   }
}

public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  m1.setName("ioi");
	  m2.setName("opopop");
	  
	  m1.start();
	  m2.start();
	  
   }
}

 

2:实现Runnable接口

public class mythread implements Runnable{
   public void run() {
	   for(int i=1;i<20;i++) {
		   System.out.println(Thread.currentThread().getName()+":"+i);
		   
	   }
   }
}


public class test {
   public static void main(String[] args) throws UnknownHostException {
	   mythread m=new mythread();
	   Thread m1=new Thread(m,"高铁");
	   Thread m2=new Thread(m,"飞机");
	   
	   System.out.println("第一="+m1.getName());
	   System.out.println("第二="+m2.getName());
	   m1.start();
	   m2.start();
	   
   }
}

(3)线程的优先级

Java使用的线程调度是抢占式调度模型,抢占式调度模型就是优先让优先级高的使用CPU,如果线程的优先级相同,那么随机一个,优先级高的线程获取的CPU时间片相对多一些。

假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。
所以说多线程程序的执行是有随机性的,因为谁抢到CPU的使用权是不一定的。

注意哈,优先级高并不一定是它先执行,它只是加大了可以拿到CPU权限的概率而已


Thread类中设置和获取线程优先级的方法
(1)public final int getPriority()   返回此线程的优先级
(2)public final void setPriority()  更改此线程的优先级
public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  
	  m1.setName("高铁");
	  m2.setName("飞机");
	  m1.setPriority(3);
	  m2.setPriority(8);
	  System.out.println("第一个线程的="+m1.getPriority());
	  System.out.println("第二个线程="+m2.getPriority());
	  m1.start();
	  m2.start();
   }
}

(4)线程的控制

1:sleep方法

public class thread extends Thread{
   public void run() {
	   for(int i=0;i<10;i++) {
		   System.out.println(Thread.currentThread().getName()+":"+i);
		   try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	   }
   }
}
//test类正常使用就行

2:join方法

public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  thread m3=new thread();
	  
	  m1.setName("高铁");
	  m2.setName("飞机");
	  m3.setName("公交");
	  
	  
	  m1.start();
//等m1这个线程死亡之后,后面的线程开始抢夺CPU的执行权限
	  try {
		m1.join();
	} catch (InterruptedException e) {
		// TODO 自动生成的 catch 块
		e.printStackTrace();
	}
	  m2.start();
	  m3.start();
   }
}

 

3:setDaemon方法

该方法用来开启守护线程,守护线程的作用就是和主线程同生共死,但是主线程结束之后,守护线程不会立即死亡,而是会挣扎几下才会死亡哦

public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  
	  m1.setName("高铁");
	  m2.setName("飞机");
	  
	  Thread.currentThread().setName("我是主线程");
	  m1.setDaemon(true);
	  m2.setDaemon(true);
	  
	  m1.start();
	  m2.start();
	  for(int i=0;i<10;i++) {
		  System.out.println(Thread.currentThread().getName()+":"+i);
	  }
   }
}

三、线程安全 

假如给你一个案列:A,B,C三个窗口卖票,票数是100张,每次顾客来买票时,票数减一,并且在控制台输出是哪一个窗口卖出的票,和当前正在出售第几张票。

如果按照正常使用线程解决该题的话,也就是如下的代码:

public class mythread implements Runnable{
	private int ticket=100;
	@Override
	public void run() {
		// TODO 自动生成的方法存根
		while(true) {
			if(ticket>0) {
				//票数大于0,,也就是有票的情况
				try {
					Thread.sleep(100);//休眠0.1秒
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
				ticket--;
			}
		}
	}
}
public class test {
   public static void main(String[] args) throws UnknownHostException {
	  mythread m=new mythread();
	  Thread s1=new Thread(m,"A");
	  Thread s2=new Thread(m,"B");
	  Thread s3=new Thread(m,"C");
	  
	  s1.start();
	  s2.start();
	  s3.start();
   }
}

 看到上面你会发现怎么出现了-1呢?

在其中假如a抢到了CPU的执行权限进入if分支,后面遇到休眠。在休眠
的这段时间内b又抢到了CPU的执行权限进入分支,进入休眠,假如这时候
a醒来后执行操作,输出,并将票数-1,假如此时票数已经是0了,后面判断
票数自然无法进入if分支了,但是如果,之前就在if分支里但是是在休眠就可以
再次进行输出和票数减一了

那么该如何解决呢?这时候就需要用到同步代码块了

public class mythread implements Runnable{

	private int ticket=100;
	private Object obj=new Object();
	@Override
	public void run() {
		// TODO 自动生成的方法存根
		
		while(true) {
		  synchronized (obj) {//同一把锁
			if(ticket>0) {
				//票数大于0,,也就是有票的情况
				
				try {
					Thread.sleep(100);//休眠0.1秒
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
				ticket--;
			}
		}
		}
			
	}
   
}

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

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

相关文章

Java学习—多线程Thread

多线程1. 线程简介1.1 普通方法和多线程1.2 程序、进程、线程2. 线程创建2.1 Thread类案例&#xff1a;下载图片2.2 Runnable接口案例&#xff1a;龟兔赛跑2.3 Callable接口3. 静态代理4. Lamda表达式5. 线程状态5.1 线程方法5.2 停止线程5.3 线程休眠5.4 线程礼让-yield5.5 Jo…

揭秘SpringMVC-DispatcherServlet之九大组件(二)

前言 上回聊到了HandlerAdapter&#xff0c;今天继续聊后面的组件。今天的主角是HandlerMapping&#xff0c;这篇文章全为他服务了。 HandlerMapping 上回说的Handler&#xff0c;我们说是处理特定请求的。也就是说&#xff0c;不是所有的请求都能处理。那么问题来了&#x…

gateway初始化与配置

1、排除依赖 spring-boot-starter-webflux 2、添加依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency><groupId>org.springf…

基于GDAL的JAVA生成GDB文件实战

前言 在之前博客中&#xff0c;陆续的介绍了关于gdb文件的读取&#xff0c;gis利器之Gdal&#xff08;三&#xff09;gdb数据读取&#xff0c;玩转GDAL一文带你深入Windows下FileGDB驱动支持&#xff0c;这些文章主要都是介绍gdal的读取gdb以及简单的gdb文件读写。在实际工作中…

VJ个人周赛

A:模拟 题意&#xff1a;给定了N个任务&#xff0c;每个任务都有一个优先级&#xff08;1~9&#xff09;&#xff0c;数字越大&#xff0c;优先级越高。将这些任务放入队列中&#xff0c;如果出队的元素&#xff08;x&#xff09;&#xff0c;x的优先级不是最高的&#xff0c;那…

从高级测试到测试开发有什么感悟

最近加入了新的团队&#xff0c;角色发生较大的转变&#xff0c;在这里分享一下自己的感受。 测试的划分 如果我们把产品的生产看成一个流水线的话&#xff0c;那么测试就是流水线上的一个重要岗位&#xff0c;把控着产品的质量。 当然&#xff0c;产品类型的不同&#xff0…

信息系统安全管理

信息系统安全是一个绕不开的话题。从事IT行业&#xff0c;不论何种角色&#xff0c;哪个工种&#xff0c;都需要有所了解。 一、信息系统安全策略 1、概述 信息系统安全策略是指对&#xff08;本单位&#xff09;信息系统的安全风险&#xff08;安全威胁&#xff09;进行有效…

小白学编程(js):通过按钮变换背景颜色

《JavaScript从入门到精通》【例9.1】 代码演示&#xff1a; <body><form class"form1" action"" name"form1" method"psot"><p><input type"button" name"Submit" value"变换背景&qu…

[附源码]计算机毕业设计基于Java的图书购物商城Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Linux常用环境配置及软件安装(持续更新)

1、jdk 1、下载jdk Linux安装包 把安装包放到自己定义的目录下 安装包网盘 提取码&#xff1a;n5hj 2、解压 解压安装包&#xff0c;输入命令&#xff1a; tar -xvf jdk-8u221-linux-x64.tar.gz 解压完成后会生成一个新文件 3、配置环境变量 编辑profile文件 vim /etc/p…

基于java+springboot+mybatis+vue+mysql的高校党务系统

项目介绍 本党务管理系统主要包括五大功能模块&#xff0c;即管理员模块、学生模块、积极分子模块、党员、党建组织。 &#xff08;1&#xff09;管理员模块&#xff1a;主要功能有&#xff1a;首页、个人中心、学生管理、学院管理、专业管理、班级管理、积极分子管理、党员管…

LeetCode HOT 100 —— 208. 实现 Trie (前缀树)

题目 Trie&#xff08;发音类似 “try”&#xff09;或者说 前缀树 是一种树形数据结构&#xff0c;用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景&#xff0c;例如自动补完和拼写检查。 请你实现 Trie类&#xff1a; Trie() 初始化前缀树对象。 vo…

postgresql_internals学习笔记(二)常规vacuum

一、 作用与原理 page pruning执行速度很快&#xff0c;但它们的作用范围毕竟只有单页、且不包含索引&#xff0c;因此&#xff0c;我们还需要更有效的清理机制。 常规vacuum是最常用的一种&#xff0c;作用范围可以是整张表&#xff0c;清理过期元组及索引项&#xff0c;并且不…

PS图层+移动工具(1)图层概念-拖动操作-移动工具基础

先打开ps软件 然后点击进入工作区 选择右上角文件 点击打开 随便选一个要操作的图片 然后看一下自己工作区右侧的 这个图层工具开了没有 如果没开 点击上方 窗口 将图层选项勾选上 这里可以看到 我们打开一个完整图片 他就只有一个图层 触发你打开的是PSD格式的图片 psd是ps…

【云计算与大数据技术】云交付模型、云部署模型、云计算优势与挑战、应用的讲解(超详细必看)

一、云交付模型 云计算主要分为三种交付模型&#xff0c;而且这三种交付模型主要是从用户体验的角度出发的&#xff0c;分别是软件即服务&#xff08;SaaS&#xff09;&#xff0c;平台即服务&#xff08;PaaS&#xff09;&#xff0c;基础设施即服务&#xff08;IaaS&#xf…

数据库建表的 15 个最佳实践方式

前言 对于后端开发同学来说&#xff0c;访问数据库&#xff0c;是代码中必不可少的一个环节。 系统中收集到用户的核心数据&#xff0c;为了安全性&#xff0c;我们一般会存储到数据库&#xff0c;比如&#xff1a;mysql&#xff0c;oracle等。 后端开发的日常工作&#xff…

string的模拟实现

目录 ​一、模拟实现中类的组织 二、默认成员函数 1.默认构造函数 2.拷贝构造函数 &#xff08;1&#xff09;传统写法——循规蹈矩 &#xff08;2&#xff09;现代写法——偷天换日 3.析构函数 4.赋值运算符重载 二、元素访问 三、容量操作 1.容量与有效数据 2.改…

SpringBootStarter技术:生产就绪与环境配置、实现自定义Starter

● Spring 官 方 Starter &#xff1a; 命 名 应 遵 循 spring-boot-starter-{name} 的 格 式 &#xff0c; 如 spring-boot-starter-web 作 为 SpringBoot Web模块的官方artifactId。 ● Spring 非 官 方 Starter &#xff1a; 命 名 应 遵 循 {name}-spring-bootstarter的格…

ModBus_RTU-上位机经RS485接口与PLC通信

目录&#xff1a; 一、预备知识 二、上位机经RS485接口与PLC通信 ---------------------------------------------------------------------------------------------------------------------- 一、预备知识 电力-ModBus_RTU通讯规约1 电力-ModBus_RTU通讯规约2 通信-R…

Java基于springboot+vue足球联赛管理系统

本足球联赛管理系统是针对目前足球联赛管理的实际需求&#xff0c;从实际工作出发&#xff0c;对过去的足球联赛管理系统存在的问题进行分析&#xff0c;完善用户的使用体会。采用计算机系统来管理信息&#xff0c;取代人工管理模式&#xff0c;查询便利&#xff0c;信息准确率…