iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java 天生就是多线程
  • 663
分享到

Java 天生就是多线程

2024-04-02 19:04:59 663人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录一、Java 中的线程1、启动2、中止3、阻塞4、深入理解run 和 start5、join 方法6、线程优先级7、守护线程8、synchronized 内置锁9、对象锁和类锁二

一、Java 中的线程

一个Java 程序从main() 方法开始执行,然后按照既定的代码逻辑执行,看似没有其他线程参与,但实际上Java

程序天生就是多线程程序,因为执行main() 方法的是一个名称为main 的线程。

public static void main(String[] args) {

// java 虚拟机线程系统的管理接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要获取同步的monitor 和synchronizer 信息,仅仅获取线程和线程堆栈信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
// 遍历线程,仅打印线程ID 和线程名称信息
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("线程ID" + threadInfo.getThreadId() + "线程名" + threadInfo.getThreadName());
}
}

上面代码输出的结果:

  • $\textcolor{red}{Monitor Ctrl-Break}$ 监控 Ctrl-Break 中断信号的
  • $\textcolor{red}{Signal Dispatcher}$ 分发处理发送给 JVM 信号的线程
  • $\textcolor{red}{ Finalizer }$ 调用对象 finalize 方法的线程
  • $\textcolor{red}{Reference Handler}$ 清除 Reference 的线程
  • $\textcolor{red}{ main }$ main 线程,用户程序入口

从上面的例子中,我们能发现,在Java中短短的几行代码,就给我们启动了5个线程,当然,不同的版本,启动的线程数量也不一样,由此我们可以得出:**Java

天生就是多线程的**

1、启动

线程的启动方式有两种(源码中的注释是这么写的)参见代码:cn.enjoyedu.ch1.base.NewThread:

  • X extends Thread;,然后 X.start
  • X implements Runnable;然后交给 Thread 运行

示例代码:(派生自Thread 类,来实现我们的两种线程启动方式)


private static class UserThread extends Thread{
@Override
public void run() {
System.out.println("UserThread.run");
}
}

private static class UserRunnable implements Runnable {

@Override
public void run() {
System.out.println("UserRunnable.run");
}
}
public static void main(String[] args) {
UserThread userThread = new UserThread();
userThread.start();
UserRunnable userRunnable = new UserRunnable();
new Thread(userRunnable).start();
}

Thread 和 Runnable 的区别:

  • Thread 是Java 里对线程的唯一抽象。
  • Runnable是Java对任务(业务逻辑)的抽象。
  • Thread可以接受任意一个Runnable的实例并执行。

2、中止

  • 线程自然终止:要么是run 执行完成了,要么是抛出了一个未处理的异常导致线程提前结束。
  • stop:暂停、恢复和停止操作对应在线程ThreadAPI就是suspend()、resume() 和 stop()。但是这些API都是过期的,不再建议使用。不建议使用的主要原因有:以suspend()方法为例,在调用后,线程不会释放已占有的资源(比如锁),而是占有资源进入睡眠状态,这样容易引发死锁问题。同样,stop() 方法在终结一个线程时,不会保证线程的资源正常释放,通常是没有给予线程完成资源释放的机会,因此会到导致程序可能工作在不确定的状态下。整因为suspend()、resume() 和 stop()方法带来的副作用,这些方法才会被标注为不建议使用的过期方法中。
  • 中断:安全的中止则是其它线程通过调用线程A的interrupt()方法对其进行中止操作,中断代表着其它线程对A线程打了个招呼,“A, 你要中断了”,不代表线程A 会立即停止自己的工作,同样A线程可以不理会这种请求。因为Java 中的线程是协作式的,不是抢占式。线程通过检查自身的中断标志位是否被置为true来进行响应。
private static class UserThread extends Thread{
public UserThread(String name){
super(name);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "interrupt flag = " + isInterrupted());
while (!isInterrupted()){
// while (!Thread.interrupted()){
// while (true){
System.out.println(threadName+ "is running");
System.out.println(threadName+ "inner interrupt flag = "+ isInterrupted());
}
System.out.println(threadName+ "interrupt flag = " + isInterrupted());
}
}
public static void main(String[] args) {
Thread endTread = new UserThread("endTread");
endTread.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 中断线程, 其实设置线程的标识位
endTread.interrupt();
}

运行上面的代码:

我们发现,在使用isInterrupted()进行线程中断的之后,isInterrupted()会返回一个true。

我们一起来看一下isInterrupted() 方法的源码:

我们再使用一下静态的 interrupted()方法,他返回的也是一个bool 值,

先看一下这个方法的源码:

从源码中我们发现,它返回也是中断标识符,但是,它把中断标识符给重新赋值成了true。

我们来看一下运行效果:

由此我们可以总结出:**线程通过方法 isInterrupted()来进行判断是否被中断,也可以调用静态方法 Thread.interrupted()来进行判断当前线程是否被中断,不过 Thread.interrupted()会同时将中断标识位改写为 false。**

3、阻塞

如果一个线程处于阻塞状态(如线程调用了 thread.sleep、thread.join、 thread.wait 等),则线程在检查中断标识时,如果发现中断标识位true,则会在这些阻塞方法调用处抛出InterruptedException 异常,并且在抛出异常后会立即将线程的中断标识位清除,即重新设置为true

private static class UserThread extends Thread{
public UserThread(String name){
super(name);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "interrupt flag = " + isInterrupted());
while (!isInterrupted()){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(threadName+ "inner interrupt flag = "+ isInterrupted());
e.printStackTrace();
}
System.out.println(threadName+ "is running");
}
System.out.println(threadName+ "interrupt flag = " + isInterrupted());
}
}
public static void main(String[] args) {
Thread endTread = new UserThread("endTread");
endTread.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 中断线程, 其实设置线程的标识位
endTread.interrupt();
}

上面代码运行结果:

那么像这种,我们该怎么去中中断操作呢?只需要在??catch?? 中调用??interrupt()?? 方法就可以了

代码运行结果:

4、深入理解run 和 start

  • Thread类是Java里对线程概念的抽象,可以这样理解:我们通过??new Thread()?? 其实只是new出一个thread的实例,还没有和操作系统中真正的线程挂起勾来。只有执行了??start()?? 方法后,才实现了真正意义上的启动线程。
  • ??start()?? 方法让一个线程进入就绪队列等待分配CPU,分到CPU后才调用??run()??方法,??start()?? 方法不能重复调用,如果重复调用,就会抛出异常。
  • run() 方法是业务逻辑实现的地方,本质上和任意一个类的任意一个成员方法并没有任何区别,可以重复执行,也可以单独调用。

那么start() 和 run() 有什么区别呢?请看代码:

private static class UserThread extends Thread{
@Override
public void run() {
int i = 90;
while (i > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am "+Thread.currentThread().getName()+"and now the i="+ i--);
}
}
}
public static void main(String[] args) {
Thread endTread = new UserThread();
endTread.setName("threadRun");
endTread.start();
}

代码运行结果:(观察运行结果,我们可以得出,调用start() 方法的时候,执行start() 方法的是子线程)

我们修改一下代码,调用??run()?? 方法

public static void main(String[] args) {
Thread endTread = new UserThread();
endTread.setName("threadRun");
endTread.run();

}

查看运行结果:(观察运行结果,我们可以得出,调用run() 方法的时候,执行run() 方法的是主线程)

5、join 方法

join() 方法是把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行。

static class Students implements Runnable {
private Thread thread;
public Students(Thread thread) {
this.thread = thread;
}
public Students() {
}
@Override
public void run() {
System.out.println("学生开始排队打饭。。。。。");
try {
if (thread != null) thread.join();
// 休眠2 秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("学生打饭完成");
}
}
static class Teacher implements Runnable {
@Override
public void run() {
try {
// 休眠2 秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老师开始打饭、、、、、");
System.out.println(Thread.currentThread().getName() + "老师打饭完成。");
}
}
public static void main(String[] args) throws InterruptedException {
Teacher teacher = new Teacher();
Thread teaThread = new Thread(teacher);
Students students = new Students(teaThread);
Thread stuThread = new Thread(students);
stuThread.start();
teaThread.start();
System.out.println("我开始打饭、、、、、");
stuThread.join();
// 让主线程休眠2 秒
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"我打饭完成");
}

代码运行结果如下:

由上代码运行结果,我们可以得出:**在线程B中调用了线程A的??join()?? 方法,只到线程A 执行完毕后,才会继续执行线程B的。**

6、线程优先级

在 Java 线程中,通过一个整型成员变量 priority 来控制优先级,优先级的范 围从 1~10,在线程构建的时候可以通过??setPriority(int)??方法来修改优先级,默认 优先级是 5,优先级高的线程分配时间片的数量要多于优先级低的线程。

设置线程优先级时,针对频繁阻塞(休眠或者I/O操作)的线程需要设置较 高优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的 优先级,确保处理器不会被独占。在不同的 JVM 以及操作系统上,线程规划会 存在差异,有些操作系统甚至会忽略对线程优先级的设定。

7、守护线程

Daemon(守护)线程是一种支持型线程,因为它主要被用作程序中后台调 度以及支持性工作。这意味着,当一个 Java 虚拟机中不存在非 Daemon 线程的 时候,Java 虚拟机将会退出。可以通过调用??Thread.setDaemon(true)??将线程设置 为Daemon线程。我们一般用不上,比如垃圾回收线程就是Daemon线程。

Daemon线程被用作完成支持性工作,但是在 Java 虚拟机退出时Daemon线 程中的??finally?? 块并不一定会执行。在构建Daemon线程时,不能依靠??finally?? 块中 的内容来确保执行关闭或清理资源的逻辑。

8、synchronized 内置锁

线程开始运行,拥有自己的栈空间,就如同一个脚本一样,按照既定的代码 一步一步地执行,直到终止。但是,每个运行中的线程,如果仅仅是孤立地运行, 那么没有一点儿价值,或者说价值很少,如果多个线程能够相互配合完成工作, 包括数据之间的共享,协同处理事情。这将会带来巨大的价值。

Java支持多个线程同时访问一个对象或者对象的成员变量,关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线 程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量 访问的可见性和排他性,又称为内置锁机制。

下面我们看一段代码,在main 方法中启动两个线程,每个线程的count 值都是10000,两个线程的和应该就是20000。

public class OnlyMain {
private long count = 0;
private Object object = new Object();
public long getCount() {
return count;
}
public void incCount() {
count++;
}
// 线程
private static class Count extends Thread {
private OnlyMain onlyMain;

public Count(OnlyMain onlyMain) {
this.onlyMain = onlyMain;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
// count = count++ = 10000
onlyMain.incCount();
}
}
}
public static void main(String[] args) throws InterruptedException {
OnlyMain onlyMain = new OnlyMain();
// 启动两个线程
Count count1 = new Count(onlyMain);
Count count2 = new Count(onlyMain);
count1.start();
count2.start();
Thread.sleep(50);
System.out.println(onlyMain.count);
}
}

代码的运行结果是:

经过多次运行,每次运行的结果都不一样,只有在很少很少的几率的情况下,才会出现正确的20000结果值,这是为什么呢?

这是因为,两个线程同时对count 成员变量进行访问,才导致输出结果的错误。怎么解决呢?使用synchronized 内置锁。

修改上面代码中的incCount() 方法,添加一个内锁:

public synchronized void incCount() {
count++;
}

这样我们就能保证每次运行的正确结果了:

9、对象锁和类锁

对象锁是用于对象实例方法的锁,或者一个对象实例上,类锁 是用于类的静态方法或一个类的class 上的,我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所有不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。

但是有一点必须要注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,类锁其实锁的是每个类的对应的class 对象。类锁和对象锁之间也是互不干扰的。

二、总结

到此这篇关于Java 天生就是多线程的文章就介绍到这了,更多相关Java 多线程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java 天生就是多线程

本文链接: https://www.lsjlt.com/news/153237.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java 天生就是多线程
    目录一、Java 中的线程1、启动2、中止3、阻塞4、深入理解run 和 start5、join 方法6、线程优先级7、守护线程8、synchronized 内置锁9、对象锁和类锁二...
    99+
    2024-04-02
  • Java实现多线程聊天室
    本文实例为大家分享了Java实现多线程聊天室的具体代码,供大家参考,具体内容如下 之前呢已经用单线程的方式来实现了聊天室,但其实它的功能并不齐全,下面用多线程来实现,功能会比单线程聊...
    99+
    2024-04-02
  • Java多线程实现多人聊天室功能
    本文为大家分享了Java多线程实现多人聊天室功能的具体代码,供大家参考,具体内容如下 1.实验目的: 编写一个 Java 应用程序,实现图形界面多人聊天室(多线程实现),要求聊天室窗...
    99+
    2024-04-02
  • Java网络编程实现多线程聊天
    本文实例为大家分享了Java网络编程实现多线程聊天的具体代码,供大家参考,具体内容如下 聊天程序如果是单线程,会导致没人只能说一句,并且说了以后,必须等到另一个人的回复,才能说第二句...
    99+
    2024-04-02
  • Java网络编程UDP实现多线程在线聊天
    本文实例为大家分享了Java实现多线程在线聊天的具体代码,供大家参考,具体内容如下 上一篇博客通过UDP实现了聊天,但只能单方面发送消息,这次实现了多线程在线聊天,也就是可以双方互发...
    99+
    2024-04-02
  • java实现多人聊天工具(socket+多线程)
    大一下学期的java期末课程设计:java实现多人聊天工具,分享一下 课设要求 多人聊天工具 服务器要求1:能够看到所有在线用户(25%) 服务器要求2:能够强制用...
    99+
    2024-04-02
  • python多线程----------主线程,子线程,任务讲解----拿下就是胜利
    这一篇博客主要介绍给分不清楚主线程.子线程的小可爱们 在之前的一篇博客中我简单的介绍了并发,并行 并发:是在时段的完成多个任务 ,但是每个时间点只有一个任务运行 而多线程就是这一个原理 非守护线程 代码: from threading im...
    99+
    2023-09-05
    开发语言 python
  • Java Socket+多线程实现多人聊天室功能
    本文实例为大家分享了Java Socket+多线程实现多人聊天室的具体代码,供大家参考,具体内容如下 思路简介 分为客户端和服务器两个类,所有的客户端将聊的内容发送给服务器,服务器接...
    99+
    2024-04-02
  • 49天精通Java,第44天,一文弄懂Java线程池 + Runnable多线程 + 调用WebService接口
    目录 一、需求很简单二、解决方案三、线程池简介1、创建方式2、核心参数3、线程池的类型(1)单线程池(2)固定线程数线程池(3)可缓存线程池(4)固定线程数,支持定时和周期性任务 ...
    99+
    2023-10-02
    线程池 高并发 网络 网络安全
  • Java网络编程怎么实现多线程聊天
    这篇文章将为大家详细讲解有关Java网络编程怎么实现多线程聊天,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。聊天程序如果是单线程,会导致没人只能说一句,并且说了以后,必须等到另一个人的回复,才能说第二句。...
    99+
    2023-06-20
  • Java多线程之哲学家就餐问题详解
    目录一、题目二、题目解析三、代码实现四、运行效果截图五、结语一、题目 教材提供一个哲学家就餐问题的解决方案的框架。本问题要求通过pthreads 互斥锁来实现这个解决方案。 哲学家...
    99+
    2024-04-02
  • 基于Java网络编程和多线程的多对多聊天系统
    目录1.前言2.类图3.代码1.前言 程序实现基于星型结构(服务器接收来自各个客户端发送的信息,然后将信息传递给其他客户端界面并在其他客户端界面显示发送的信息) 2.类图 3.代...
    99+
    2024-04-02
  • Java多线程局域网聊天室的实现
    目录1.TCP2.套接字3.C/S架构4.多线程5.服务器客户端局域网聊天室 在学习了一个学期的java以后,觉得java真是博大精深,彻底放弃了因为c++而轻视java的心态,搞了...
    99+
    2024-04-02
  • java多线程从入门到精通看这篇就够了
    目录一.认识线程及线程的创建1.线程的概念2.线程的特性3.线程的创建方式<1>继承Thread类<2>实现Runnable接口<3>实现Call...
    99+
    2024-04-02
  • JAVA多线程
     林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka        写在前面的话:此文只能说是java多线程的一个入门,其实Java里头...
    99+
    2023-06-02
  • Java创建多线程局域网聊天室实例
    局域网聊天室 在学习了一个学期的java以后,觉得java真是博大精深,彻底放弃了因为c++而轻视java的心态,搞了一个多线程的聊天室,熟悉了一下服务器和客户机的操作。 1.TCP...
    99+
    2024-04-02
  • java中多线程和线程安全是什么
    这篇文章给大家分享的是有关java中多线程和线程安全是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是进程?电脑中时会有很多单独运行的程序,每个程序有一个独立的进程,而进程之间是相互独立存在的。比如下图中...
    99+
    2023-06-25
  • 怎么用Java Socket+多线程实现多人聊天室功能
    这篇文章主要讲解了“怎么用Java Socket+多线程实现多人聊天室功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Java Socket+多线程实现多人聊天室功能”吧!思路简介分...
    99+
    2023-06-20
  • Java多线程是什么意思
    这篇文章主要讲解了“Java多线程是什么意思”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程是什么意思”吧!多线程(multiple thread)是计算机实现多任务并行处理的一...
    99+
    2023-06-02
  • java多线程机制是什么
    本篇内容主要讲解“java多线程机制是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java多线程机制是什么”吧!一、程序、进程、线程1.1 什么是程序程序(program):是为完成特定任...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作