当前位置: 首页 > news >正文

Java 之多线程基础

1. 什么是多线程?

多线程是指在单个程序中同时执行多个任务。就像一个家庭,多个家庭成员可以同时进行不同的活动,比如做饭、洗衣服、看电视等等。

生活中的例子:

  • 浏览器同时打开多个网页,每个网页都运行在独立的线程中。

  • 手机同时运行着多个应用程序,比如音乐播放器、导航软件和聊天软件等等,这些应用都运行在不同的线程中。

2. 并行和并发

  • 并发:是指多个任务在同一时间段内进行,但是可能不是真正同时执行,而是通过时间片轮流执行。就像一个厨师,可以同时炒菜和煮汤,但实际操作上是先炒菜几分钟,然后再去煮汤几分钟,不断切换。

  • 并行:是指多个任务在同一时间点同时执行,需要多个处理器才能实现。就像两个人一起做菜,一个炒菜,一个煮汤,真正的同时进行。

生活中的例子:

  • 并发:一台单核电脑,可以同时运行多个程序,但是实际上是操作系统将CPU时间分配给不同的程序,轮流执行。

  • 并行:一台多核电脑,可以同时运行多个程序,每个程序都运行在不同的处理器上,真正同时执行。

3. 进程和线程

  • 进程:是操作系统分配资源的最小单位,包含程序代码、数据和系统资源等。可以理解为一个独立运行的程序,比如浏览器、音乐播放器等等。

  • 线程:是进程中的一个执行单元,共享进程的资源,是CPU调度和执行的最小单位。可以理解为一个进程中的一个任务,比如浏览器中的多个网页、音乐播放器中的播放和暂停等。

区别:

  • 进程独立运行,拥有自己的内存空间,线程共享进程的内存空间。

  • 进程之间通信相对困难,线程之间通信比较容易。

  • 进程切换开销大,线程切换开销小。

4. 实现线程的四种方式

4.1 继承 Thread 类:

public class MyThread extends Thread {@Overridepublic void run() {System.out.println("我是线程:" + Thread.currentThread().getName());}public static void main(String[] args) {MyThread thread = new MyThread();thread.setName("线程1");thread.start();}
}

4.2 实现 Runnable 接口:

public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("我是线程:" + Thread.currentThread().getName());}public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable, "线程2");thread.start();}
}

4.3 实现 Callable 接口:

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "我是线程:" + Thread.currentThread().getName();}public static void main(String[] args) throws Exception {MyCallable callable = new MyCallable();FutureTask<String> futureTask = new FutureTask<>(callable);Thread thread = new Thread(futureTask, "线程3");thread.start();System.out.println(futureTask.get());}
}

4.4 使用线程池:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPool {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);executor.execute(() -> System.out.println("我是线程:" + Thread.currentThread().getName()));executor.shutdown();}
}

四种方式的异同和优缺点:

方式优点缺点
继承 Thread 类代码简洁无法继承其他类
实现 Runnable 接口可继承其他类代码略复杂
实现 Callable 接口可返回结果代码略复杂
线程池管理线程,提高效率使用相对复杂

5. 线程休眠、优先级和守护线程

5.1 线程休眠:

  • 概念:让线程暂停一段时间,让其他线程运行。

  • 方法:Thread.sleep(long millis)

  • 示例

public class SleepThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("我是线程:" + Thread.currentThread().getName() + ",i = " + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

5.2 线程优先级

  • 概念:设置线程的优先级,优先级高的线程更容易获得CPU时间片。

  • 方法:Thread.setPriority(int priority),优先级范围为 1(最低)到 10(最高),默认5。

  • 示例

public class PriorityThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("我是线程:" + Thread.currentThread().getName() + ",i = " + i);}}
}public class PriorityTest {public static void main(String[] args) {PriorityThread thread1 = new PriorityThread();thread1.setName("线程1");thread1.setPriority(Thread.MIN_PRIORITY);PriorityThread thread2 = new PriorityThread();thread2.setName("线程2");thread2.setPriority(Thread.MAX_PRIORITY);thread1.start();thread2.start();}
}

5.3 守护线程:

  • 概念:守护线程是为其他线程服务的,当所有用户线程都结束时,守护线程也会自动结束。

  • 方法:Thread.setDaemon(true)

  • 示例

public class DaemonThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("我是守护线程,正在运行...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class DaemonTest {public static void main(String[] args) {DaemonThread daemonThread = new DaemonThread();daemonThread.setDaemon(true);daemonThread.start();System.out.println("我是主线程,即将结束...");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}
}

总结:

多线程是Java程序中重要的并发机制,可以提高程序效率,实现更复杂的应用。了解并行和并发、进程和线程的区别、实现线程的四种方式以及线程相关的概念,如休眠、优先级和守护线程,是学习Java多线程的基础。希望对各位看官有所帮助,感谢各位看官的观看,也祝大家今天中秋快乐,下期见,谢谢~


http://www.mrgr.cn/news/28761.html

相关文章:

  • 【Linux】进程的概念
  • 使用OpenCV(C++)通过鼠标点击操作获取图像的像素坐标和像素值
  • 力扣 二叉树的直径-543
  • 秃姐学AI系列之:样式迁移 + 代码实现
  • ECharts 实现大屏地图功能
  • 递归探秘:从斐波那契数列到迷宫求解
  • neo4j(spring) 使用示例
  • Linux:RPM软件包管理以及yum软件包仓库
  • 用 Python 实现将长 Markdown 文档从二级标题开始拆分
  • 【车载以太网】【SOME/IP】vsomeip代码解析--routing_manager
  • 【课程学习】信号检测与估计II
  • NC 排序
  • 硬件工程师笔试面试——显示器件
  • fiddler抓包03_汉化
  • 基于代理的分布式身份管理方案
  • Linux:软件包管理器 yum和编辑器-vim使用
  • 『功能项目』回调函数处理死亡【54】
  • leetcode-枚举算法
  • Redhat 8/9 缺少 compat-db47
  • SpringBoot开发——统一返回和统一异常处理
  • idea一个窗口打开多个仓库的代码
  • 硬件工程师笔试面试——无线通讯模块
  • string的模拟实现and友元
  • VS Code + WSL 用法摘记
  • 4.提升客户服务体验:ChatGPT在客服中的应用(4/10)
  • canal消费binlog异常排查