首页 > 编程知识 正文

java多线程知识点归纳总结(Java多线程编程实战指南核心篇)

时间:2023-12-19 12:29:25 阅读:317736 作者:VKUP

本文目录一览:

北大青鸟java培训:Java多线程问题总结?

Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多、越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的。

java课程培训机构认为这篇文章主要是对多线程的问题进行总结的,因此罗列了多个多线程的问题。

这些多线程的问题,有些来源于各大网站、有些来源于自己的思考。

(1)发挥多核CPU的优势随着工业的进步,现在的笔记本、台式机乃至商用的应用服务器至少也都是双核的,4核、8核甚至16核的也都不少见,如果是单线程的程序,那么在双核CPU上就浪费了50%,在4核CPU上就浪费了75%。

单核CPU上所谓的”多线程”那是假的多线程,同一时间处理器只会处理一段逻辑,只不过线程之间切换得比较快,看着像多个线程”同时”运行罢了。

多核CPU上的多线程才是真正的多线程,它能让你的多段逻辑同时工作,多线程,可以真正发挥出多核CPU的优势来,达到充分利用CPU的目的。

(2)防止阻塞从程序运行效率的角度来看,单核CPU不但不会发挥出多线程的优势,反而会因为在单核CPU上运行多线程导致线程上下文的切换,而降低程序整体的效率。

但是单核CPU我们还是要应用多线程,就是为了防止阻塞。

试想,如果单核CPU使用单线程,那么只要这个线程阻塞了,比方说远程读取某个数据吧,对端迟迟未返回又没有设置超时时间,那么你的整个程序在数据返回回来之前就停止运行了。

多线程可以防止这个问题,多条线程同时运行,哪怕一条线程的代码执行读取数据阻塞,也不会影响其它任务的执行。

(3)便于建模这是另外一个没有这么明显的优点了。

假设有一个大的任务A,单线程编程,那么就要考虑很多,建立整个程序模型比较麻烦。

但是如果把这个大的任务A分解成几个小任务,任务B、任务C、任务D,分别建立程序模型,并通过多线程分别运行这几个任务,那就简单很多了。

Java学习有哪些重点和难点

 Java学习第一个重点难点——JDK开发环境安装

首先是Java开发环境的各种版本选择,一般情况下我们需要从JDK官网下载最新版本的JDK文件(但是还需要注意你所学习的图书或者视频使用的是哪个版本的JDK),根据自己电脑的系统选择对应的安装包。

其次在安装过程中一定要设置环境变量的路径,这个过程非常关键,会直接影响你的JDK是否可以正常使用。最终还要在“命令提示符”中验证,是否已经真正地完成了JDK的安装。

Java学习第二个重点难点——变量的理解

变量是入门Java开发的首个概念性的思维转变,目前所有的编程语言都是完成人类语言到机器语言的转变过渡方式。变量则是贯穿整个Java编程开发的核心知识点。例如变量的各种不同的类型、变量的命名规则、变量之间的转换、变量赋值时的初始化的理解,变量的相关运算符的使用等等。

Java学习第三个重点难点——OOP面向对象编程思想

Java作为高级编程语言,最大的特点就是采用面向对象编程思想,与面向过程的编程方法相比,OOP能够大幅度的提高代码运行效率。在面向对象中需要重点理解类、对象、抽象类、接口、封装、集成和多态的概念。在Java编程开发中,大部分实战项目都是采用面向对象的思维进行开发,因此重点理解和掌握OOP是学习Java编程开发的重中之重。所以掌握面向对象的概念并且能够熟练运用是一个Java开发工程师最基本要求。在学习过程中,应该尽可能多地去进行实操练习。

Java学习第四个重点难点——多线程

在大型项目中,多线程是众多Java程序员的技术门槛,单纯的概念理解可能并不是很困难,最重要的是要掌握多线程的核心原理以及多线程的实际应用。包括多线程的创建、现成的 生命周期、锁的概念、线程安全等问题。在实际编程开发中,多线程是出现BUG最多的位置,而避免BUG出现的最好方法就是深刻理解多线程的原理,总结归纳多线程经常出现异常的位置,并快速响应找到对应的解决方案。

Java学习中的第五个重点难点——异常

异常是每一个Java开发者不可避免的问题。包括Error、Runtime Exception、Exception、throw自定义异常等等。之前接触到很多同学遇到异常就会手忙脚乱,其实大部分异常都是可以通过调式解决掉,也有很多异常是由于开发者的编码错误引发的,因此遇到异常首先要分析异常产生的原因,逐层去调式获取引发异常的位置,然后不断的总结归纳引发异常的各种原因,在学习工作中不断的提高自己解决问题的能力。学习异常的方法有两种,一种就是系统地去了解各种异常的种类,并理解其引发异常的原因,在实际遇到问题的时候先套用方法,然后再寻找不同的解决方案。另外一种方法就是学习中进行大量的练习,在练习过程中遇到异常后根据实际情况去排查异常产生原因并总结归纳。

Java学习中的其他重点难点

虽然在文中没有重点提到循环、构造函数、I/O和序列化、各种设计模式等等关键内容。对于初学者来说,每一个新的知识点都有一个理解到运用的过程,最重要的是能在学习中掌握所学知识点的底层原理和实际应用。Java编程开发作为一门实操性非常强的技术,单纯的理论知识无法支撑你的快速就业,能够真正动手编码并实现相应的功能才是学习Java最终的目的。

在 Java 程序中怎么保证多线程的运行安全?

零基础学习java可按照这份大纲来进行学习

第一阶段:Java专业基础课程

阶段目标:

1. 熟练掌握Java的开发环境与编程核心知识

2. 熟练运用Java面向对象知识进行程序开发

3. 对Java的核心对象和组件有深入理解

4. 熟练应用JavaAPI相关知识

5. 熟练应用JAVA多线程技术

6. 能综合运用所学知识完成一个项目

知识点:

1、基本数据类型,运算符,数组,掌握基本数据类型转换,运算符,流程控制。

2、数组,排序算法,Java常用API,类和对象,了解类与对象,熟悉常用API。

3、面向对象特性,集合框架,熟悉面向对象三大特性,熟练使用集合框架。

4、IO流,多线程。

5、网络协议,线程运用。

第二阶段:JavaWEB核心课程

阶段目标:

1. 熟练掌握数据库和MySQL核心技术

2. 深入理解JDBC与DAO数据库操作

3. 熟练运用JSP及Servlet技术完成网站后台开发

4. 深入理解缓存,连接池,注解,反射,泛型等知识

5. 能够运用所学知识完成自定义框架

知识点:

1、数据库知识,范式,MySQL配置,命令,建库建表,数据的增删改查,约束,视图,存储过程,函数,触发器,事务,游标,建模工具。

2、深入理解数据库管理系统通用知识及MySQL数据库的使用与管理。为Java后台开发打下坚实基础。Web页面元素,布局,CSS样式,盒模型,JavaScript,jQuery。

3、掌握前端开发技术,掌握jQuery。

4、Servlet,EL表达式,会话跟踪技术,过滤器,FreeMarker。

5、掌握Servlet相关技术,利用Servlet,JSP相关应用技术和DAO完成B/S架构下的应用开发。

6、泛型,反射,注解。

7、掌握JAVA高级应用,利用泛型,注解,枚举完成自己的CRUD框架开发为后续框架学习做铺垫。

8、单点登录,支付功能,项目整合,分页封装熟练运用JSP及Servlet核心知识完成项目实战。

第三阶段:JavaEE框架课程

阶段目标:

1. 熟练运用Linux操作系统常见命令及完成环境部署和Nginx服务器的配置

2. 熟练运用JavaEE三大核心框架:Spring,SpringMVC,MyBatis

3. 熟练运用Maven,并使用SpringBoot进行快速框架搭建

4. 深入理解框架的实现原理,Java底层技术,企业级应用等

5. 使用Shiro,Ztree和Spring,SpringMVC,Mybaits完成企业项目

知识点:

1、Linux安装配置,文件目录操作,VI命令,管理,用户与权限,环境部署,Struts2概述,hiberante概述。

2、Linux作为一个主流的服务器操作系统,是每一个开发工程师必须掌握的重点技术,并且能够熟练运用。

3、SSH的整合,MyBatis,SpringMVC,Maven的使用。

4、了解AOP原理,了解中央控制器原理,掌握MyBatis框架,掌握SSM框架的整合。

5、Shiro,Ztree,项目文档,项目规范,需求分析,原型图设计,数据库设计,工程构建,需求评审,配置管理,BUG修复,项目管理等。

6、独立自主完成一个中小型的企业级综合项目的设计和整体架构的原型和建模。独立自主完成一个大型的企业级综合项目,并具备商业价值

北大青鸟设计培训:java多线程编程中涉及的基础知识点?

线程设计在软件开发领域中是非常常见的一个设计构成,今天合肥北大青鸟就一起来了解一下,java多线程编程中都涉及到了哪些基础知识点。

顺序用于表示多个操作“依次处理”。

比如把十个操作交给一个人来处理时,这个人要一个一个地按顺序来处理并行用于标识多个操作“同时处理”。

比如十个操作分给两个人处理时,这两个人就会并行来处理。

并发相对于顺序和并行来说比较抽象,用于表示“将一个操作分割成多个部分并且允许无序处理”。

比如将十个操作分成相对独立的两类,这样便能够开始并发处理了。

如果一个人来处理,这个人就是顺序处理分开的并发操作,而如果是两个人,这两个人就可以并行处理同一个操作。

总结多线程程序都是并发处理的。

如果CPU只有一个,那么并发处理就是顺序执行的,而如果有多个CPU,那么并发处理就可能会并行运行。

等待队列所有实例都拥有一个等待队列,它是在实例的wait方法执行后停止操作的线程队列。

就好比为每个实例准备的线程休息室在执行wait方法后,线程便会暂停操作,进入等待队列这个休息室。

除非发生下列某一情况,否则线程会一直在等待队列中休眠。

有其他线程的notify方法来唤醒线程有其他线程的notifyAll方法来唤醒线程有其他线程的interrupt方法来唤醒线程wait方法超时notify方法该方法会将等待队列中的一个线程去除。

同wait方法一样,若要执行notify方法,线程也必须持有要调用的实例的锁。

notifyAll方法notify方法仅唤醒一个线程,而notifyAll则唤醒所有线程,这是两者之间的区别同wait方法和notify方法一样,notifyAll方法也只能由持有要调用的实例锁的线程调用notify和notifyAll选择notify方法和notifyAll方法非常相似,到底该使用哪个?实际上,这很难选择,由于notify唤醒的线程较少,所以处理速度要比使用notifyAll时快。

但使用notify时,如果处理不好,程序便可能会停止。

一般来说,使用notifyAll时的代码要比使用notify时的更为健壮。

多线程回顾笔记总结

三种创建方式:

// 练习Thread,实现多线程同步下载图片

public class TestThread1 extends Thread {

private String name; // 保存文件名

// 创建一个构造器

public TestThread1(String url, String name) {

this.url = url;

this.name = name;

}

public static void main(String[] args) {

TestThread1 testThread1 = new TestThread1(";z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=4spn=0di=179850pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1462782358%2C2840615474os=332435882%2C2135675601simid=3516664974%2C458125993adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3B8-jyj_z%26e3BvgAzdH3FQQ%25E0%25l9%25AF%25EF%25Bl%25ba%25E0%25ln%25A0%25Em%25BE%25Bm%25Em%25lD%25l8%25Ec%25b9%25lA_z%26e3Bip4sgsm=5islist=querylist=","1.jpg");

TestThread1 testThread2 = new TestThread1(";z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=8spn=0di=18480pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1756505232%2C2129310927os=3725694615%2C3696011658simid=3576571828%2C474240706adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3F80qq_z%26e3Bv54AzdH3Fqqp57xtwg2AzdH3F8899l9m_rn_z%26e3Bip4sgsm=5islist=querylist=","2.jpg");

TestThread1 testThread3 = new TestThread1(";z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=25spn=0di=132220pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1226648351%2C4217836os=1652635041%2C3404961290simid=3325093720%2C338083432adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bprbb_z%26e3BgjpAzdH3Fp57xtwg2p7rtwgAzdH3Fgwgfijg2p57xtwg2AzdH3Fda8lAzdH3F8d89AzdH3F8dnb0_z%26e3Bip4sgsm=5islist=querylist=","3.jpg");

testThread1.start();

testThread2.start();

testThread3.start();

/* 结果,说明线程不是按代码先后顺序执行的,是同时执行的

下载了文件,名为:3.jpg

下载了文件,名为:1.jpg

下载了文件,名为:2.jpg

*/

}

// 下载图片的线程执行体

@Override

public void run() {

WebDownLoader webDownLoader = new WebDownLoader();

webDownLoader.downLoader(url,name);

System.out.println("下载了文件,名为:"+name);

}

}

// 下载器

class WebDownLoader {

// 下载方法

public void downLoader(String url,String name) {

try {

// copyURLToFile(),这个方法就是把网上的一个url变成一个文件

FileUtils.copyURLToFile(new URL(url),new File(name));

} catch (IOException e) {

e.printStackTrace();

System.out.println("IO异常,downLoader方法出错");

}

}

}

// 创建线程方式2:实现Runnable接口,重写run()方法,执行线程需要丢入Runnable接口实现类,调用start()方法

public class TestThread2 implements Runnable {

public static void main(String[] args) {

// 创建Runnable 接口实现类对象

TestThread2 testThread2 = new TestThread2();

// 创建线程对象,通过线程对象来开启我们的线程,代理

Thread thread = new Thread(testThread2);

thread.start();

//new Thread(testThread2).start(); // 简写方法

for (int i = 0; i 2000; i++) {

System.out.println("我们在学习多线程---"+i);

}

}

@Override

public void run() {

for (int i = 0; i 2000; i++) {

System.out.println("我们在玩 游戏 啦---"+i);

}

}

}

发现问题:多个线程操作同一个资源情况下,线程不安全,数据紊乱,出现重复数据

// 模拟龟兔赛跑

public class Race implements Runnable {

// 胜利者

private static String winner;

@Override

public void run() {

for (int i = 0; i = 100) {

winner = Thread.currentThread().getName();

System.out.println("winner is " + winner);

return true;

}

}

return false;

}

public static void main(String[] args) {

Race race = new Race();

new Thread(race, "兔子").start();

new Thread(race, "乌龟").start();

}

}

关闭服务:executorService.shutdownNow();

// 线程创建方式三:实现Callable接口

/*

* Callable的好处

* 1.可以定义返回值

* 2.可以抛出异常

**/

public class TestCallable implements Callable {

private String name; // 保存文件名

// 创建一个构造器

public TestCallable(String url, String name) {

this.url = url;

this.name = name;

}

public static void main(String[] args) throws ExecutionException, InterruptedException {

TestCallable testThread1 = new TestCallable(";z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=4spn=0di=179850pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1462782358%2C2840615474os=332435882%2C2135675601simid=3516664974%2C458125993adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3B8-jyj_z%26e3BvgAzdH3FQQ%25E0%25l9%25AF%25EF%25Bl%25ba%25E0%25ln%25A0%25Em%25BE%25Bm%25Em%25lD%25l8%25Ec%25b9%25lA_z%26e3Bip4sgsm=5islist=querylist=","1.jpg");

TestCallable testThread2 = new TestCallable(";z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=8spn=0di=18480pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1756505232%2C2129310927os=3725694615%2C3696011658simid=3576571828%2C474240706adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3F80qq_z%26e3Bv54AzdH3Fqqp57xtwg2AzdH3F8899l9m_rn_z%26e3Bip4sgsm=5islist=querylist=","2.jpg");

TestCallable testThread3 = new TestCallable(";z=0ipn=falseword=qq%E5%A4%B4%E5%83%8Fhs=0pn=25spn=0di=132220pi=0rn=1tn=baiduimagedetailis=0%2C0ie=utf-8oe=utf-8cl=2lm=-1cs=1226648351%2C4217836os=1652635041%2C3404961290simid=3325093720%2C338083432adpicid=0lpn=0ln=30fr=alafm=sme=cg=headbdtype=0oriquery=qq%E5%A4%B4%E5%83%8Fobjurl=http%3A%2F%2F;fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bprbb_z%26e3BgjpAzdH3Fp57xtwg2p7rtwgAzdH3Fgwgfijg2p57xtwg2AzdH3Fda8lAzdH3F8d89AzdH3F8dnb0_z%26e3Bip4sgsm=5islist=querylist=","3.jpg");

// 创建执行服务

ExecutorService executorService = Executors.newFixedThreadPool(3);

// 提交执行

Future submit1 = executorService.submit(testThread1);

Future submit2 = executorService.submit(testThread2);

Future submit3 = executorService.submit(testThread3);

// 获取结果

Boolean b1 = submit1.get();

Boolean b2 = submit2.get();

Boolean b3 = submit3.get();

// 关闭服务

executorService.shutdownNow();

System.out.println(b1);

System.out.println(b2);

System.out.println(b3);

/* 结果,说明线程不是按代码先后顺序执行的,是同时执行的

下载了文件,名为:3.jpg

下载了文件,名为:1.jpg

下载了文件,名为:2.jpg

*/

}

// 下载图片的线程执行体

@Override

public Boolean call() {

WebDownLoader webDownLoader = new WebDownLoader();

webDownLoader.downLoader(url,name);

System.out.println("下载了文件,名为:"+name);

return true;

}

}

// 下载器

class WebDownLoader {

// 下载方法

public void downLoader(String url,String name) {

try {

// copyURLToFile(),这个方法就是把网上的一个url变成一个文件

FileUtils.copyURLToFile(new URL(url),new File(name));

} catch (IOException e) {

e.printStackTrace();

System.out.println("IO异常,downLoader方法出错");

}

}

}

静态代理模式总结:

真实对象和代理对象都要实现同一个接口

代理对象要代理真实角色

代理模式的好处:

代理对象可以做很多真实对象做不了的事情

真实对象专注做自己的事情就可以了, 其他的事情交给代理公司来做

new Thread(()- System.out.println("我爱你啊")).start();

public abstract void run();

}

五大状态:

// 测试Stop

// 1.建议线程正常停止,利用次数,不建议死循环

// 2.建议使用标志位,设置一个标志位

// 3.不要使用stop(),destroy()方法,已过时

public class StopTest implements Runnable {

// 1 设置一个标志位

private boolean flag = true;

public static void main(String[] args) {

StopTest stopTest = new StopTest();

// 开启线程

new Thread(stopTest).start();

for (int i = 0; i 1000; i++) {

System.out.println("main Thread is running..."+i);

if (i == 900) {

// 调用stop方法切换标志位停止线程

stopTest.stop();

System.out.println("Thread is stopped...");

}

}

}

// 设置一个公开的方法停止线程,转换标志位

public void stop() {

this.flag = false;

}

@Override

public void run() {

int i = 0;

while (flag) {

System.out.println("Thread is running..."+ i++);

}

}

}

yield

jion

daemon

// 化妆的方法,互相持有对方的锁,就是需要拿到对方的资源

private void makeup() throws InterruptedException {

if (choice == 0) {

synchronized (lipstick) { // 获得口红的锁

System.out.println(this.girlName+"获得口红的锁");

Thread.sleep(1000);

synchronized (mirror) { // 一秒后想获得镜子的锁

System.out.println(this.girlName+"获得镜子的锁");

}

}

} else {

synchronized (mirror) { // 获得镜子的锁

System.out.println(this.girlName+"获得镜子的锁");

Thread.sleep(2000);

synchronized (lipstick) { // 一秒后想获得口红的锁

System.out.println(this.girlName+"获得口红的锁");

}

}

}

}

这样synchronized 块包裹着,就会导致程序卡死,只要不包裹着,就可以正常运行,如下:

// 死锁,多个线程互相抱着对方需要的资源,然后形成僵持

public class DeadLock {

public static void main(String[] args) {

Makeup bestGirl = new Makeup(0, "婕儿");

Makeup betterGirl = new Makeup(1, "珂儿");

bestGirl.start();

betterGirl.start();

}

}

// 口红

class Lipstick {

}

// 镜子

class Mirror {

}

// 化妆

class Makeup extends Thread {

// 需要的资源只有一份,用static来保证只有一份

static Mirror mirror = new Mirror();

static Lipstick lipstick = new Lipstick();

int choice; // 选择

String girlName; // 使用化妆品的人

public Makeup(int choice, String girlName) {

this.choice = choice;

this.girlName = girlName;

}

@Override

public void run() {

// 化妆

try {

makeup();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

// 化妆的方法,互相持有对方的锁,就是需要拿到对方的资源

private void makeup() throws InterruptedException {

if (choice == 0) {

synchronized (lipstick) { // 获得口红的锁

System.out.println(this.girlName+"获得口红的锁");

Thread.sleep(1000);

}

synchronized (mirror) { // 一秒后想获得镜子的锁

System.out.println(this.girlName+"获得镜子的锁");

}

} else {

synchronized (mirror) { // 获得镜子的锁

System.out.println(this.girlName+"获得镜子的锁");

Thread.sleep(2000);

}

synchronized (lipstick) { // 一秒后想获得口红的锁

System.out.println(this.girlName+"获得口红的锁");

}

}

}

}

上面列出了死锁的四个条件,我们只要想办法破其中任意一个,或多个条件就可以避免死锁发生

1.这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件.

2.Java提供了几个方法解决线程之间的通信问题

3.解决方式1

并发协作模型“生产者/消费者模式” —管程法

生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据

4.解决方式2

// 测试线程池

public class PoolTest {

public static void main(String[] args) {

// 创建服务,创建池子

// newFixedThreadPool,参数为:线程池池子大小

ExecutorService service = Executors.newFixedThreadPool(10);

service.execute(new MyThread());

service.execute(new MyThread());

service.execute(new MyThread());

service.execute(new MyThread());

// 2.关闭连接

service.shutdown();

}

}

class MyThread implements Runnable {

@Override

public void run() {

System.out.println(Thread.currentThread().getName());

}

}

什么是Java多线程

多线程的概念?

说起多线程,那么就不得不说什么是线程,而说起线程,又不得不说什么是进程。

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

进程可以简单的理解为一个可以独立运行的程序单位。它是线程的集合,进程就是有一个或多个线程构成的,每一个线程都是进程中的一条执行路径。

那么多线程就很容易理解:多线程就是指一个进程中同时有多个执行路径(线程)正在执行。

为什么要使用多线程?

1.在一个程序中,有很多的操作是非常耗时的,如数据库读写操作,IO操作等,如果使用单线程,那么程序就必须等待这些操作执行完成之后才能执行其他操作。使用多线程,可以在将耗时任务放在后台继续执行的同时,同时执行其他操作。

2.可以提高程序的效率。

3.在一些等待的任务上,如用户输入,文件读取等,多线程就非常有用了。

缺点:

1.使用太多线程,是很耗系统资源,因为线程需要开辟内存。更多线程需要更多内存。

2.影响系统性能,因为操作系统需要在线程之间来回切换。

3.需要考虑线程操作对程序的影响,如线程挂起,中止等操作对程序的影响。

4.线程使用不当会发生很多问题。

总结:多线程是异步的,但这不代表多线程真的是几个线程是在同时进行,实际上是系统不断地在各个线程之间来回的切换(因为系统切换的速度非常的快,所以给我们在同时运行的错觉)。

2.多线程与高并发的联系。

高并发:高并发指的是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统集中大量访问或者socket端口集中性收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。如果高并发处理不好,不仅仅降低了用户的体验度(请求响应时间过长),同时可能导致系统宕机,严重的甚至导致OOM异常,系统停止工作等。如果要想系统能够适应高并发状态,则需要从各个方面进行系统优化,包括,硬件、网络、系统架构、开发语言的选取、数据结构的运用、算法优化、数据库优化……。

而多线程只是在同/异步角度上解决高并发问题的其中的一个方法手段,是在同一时刻利用计算机闲置资源的一种方式。

多线程在高并发问题中的作用就是充分利用计算机资源,使计算机的资源在每一时刻都能达到最大的利用率,不至于浪费计算机资源使其闲置。

3.线程的创建,停止,常用方法介绍。

1.线程的创建:

线程创建主要有2种方式,一种是继承Thread类,重写run方法即可;(Thread类实现了Runable接口)

另一种则是实现Runable接口,也需要重写run方法。

线程的启动,调用start()方法即可。 我们也可以直接使用线程对象的run方法,不过直接使用,run方法就只是一个普通的方法了。

其他的还有: 通过匿名内部类的方法创建;实现Callable接口。。。。。

2.线程常用方法:

currentThread()方法:该方法返回当前线程的信息 .getName()可以返回线程名称。

isAlive()方法:该方法判断当前线程是否处于活动状态。

sleep()方法:该方法是让“当前正在执行的线程“休眠指定的时间,正在执行的线程是指this.currentThread()返回的线程。

getId()方法:该方法是获取线程的唯一标识。

3.线程的停止:

在java中,停止线程并不简单,不想for。。break那样说停就停,需要一定的技巧。

线程的停止有3种方法:

1.线程正常终止,即run()方法运行结束正常停止。

2.使用interrupt方法中断线程。

3.使用stop方法暴力停止线程。

interrupt方法中断线程介绍:

interrupt方法其实并不是直接中断线程,只是给线程添加一个中断标志。

判断线程是否是停止状态:

this.interrupted(); 判断当前线程是否已经中断。(判断的是这个方法所在的代码对应的线程,而不是调用对象对应的线程)

this.isInterrupted(); 判断线程是否已经中断。(谁调用,判断谁)

注:.interrupted()与isInterrupted()的区别:

interrupted()方法判断的是所在代码对应的线程是否中断,而后者判断的是调用对象对应的线程是否停止

前者执行后有清除状态的功能(如连续调用两次时,第一次返回true,则第二次会返回false)

后者没有清除状态的功能(两次返回都为true)

真正停止线程的方法:

异常法:

在run方法中 使用 this.interrupted();判断线程终止状态,如果为true则 throw new interruptedException()然后捕获该异常即可停止线程。

return停止线程:

在run方法中 使用 this.interrupted();判断线程终止状态,如果为true则return停止线程。 (建议使用异常法停止线程,因为还可以在catch中使线程向上抛,让线程停止的事件得以传播)。

暴力法:

使用stop()方法强行停止线程(强烈不建议使用,会造成很多不可预估的后果,已经被标记为过时)

(使用stop方法会抛出 java.lang.ThreadDeath 异常,并且stop方法会释放锁,很容易造成数据不一致)

注:在休眠中停止线程:

在sleep状态下停止线程 会报异常,并且会清除线程状态值为false;

先停止后sleep,同样会报异常 sleep interrupted;

4.守护线程。

希望对您有所帮助!~

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。