Java多线程编程基础与高级特性

news2024/10/8 22:09:03

在现代软件开发中,多线程编程是一个重要的概念,它能够充分利用多核处理器的能力,提高程序的执行效率。Java 语言内置了对多线程的支持,使得开发者可以方便地创建和管理线程。

创建线程

1. 继承Thread类

这是最直接的方式,通过创建一个继承自Thread类的子类,并重写run()方法来定义线程的行为。之后,创建该子类的实例并调用start()方法来启动线程。

实现步骤:
1. 创建一个继承自Thread类的子类。
2. 重写run()方法,定义线程的执行逻辑。
3. 创建子类的实例。
4. 调用start()方法启动线程。

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
    }

    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}

2. 实现Runnable接口

这种方式更为推荐,因为它符合面向接口编程的原则,且不会受到单继承的限制。创建一个实现了 Runnable接口的类,实现run()方法。然后将Runnable实例传递给Thread类的构造器,最后调用Thread对象的start()方法来启动线程。

实现步骤:
1. 创建一个实现Runnable接口的类。
2. 实现run()方法,定义线程的执行逻辑。
3. 创建Runnable接口的实现类的实例。
4. 将Runnable实例传递给Thread类的构造器,创建Thread对象。
5. 调用Thread对象的start()方法启动线程。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 通过 Runnable 运行");
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable(), "MyRunnableThread");
        thread.start(); // 启动线程
    }
}

3. 实现Callable接口

与Runnable接口类似,Callable接口也代表了一个任务,但它可以返回结果并且可以抛出异常。Callable接口中的call()方法返回一个结果值,并且可能抛出异常。通常,Callable任务的结果会被Future对象包装起来,通过ExecutorService执行Callable任务。

实现步骤:
1. 创建一个实现Callable接口的类。
2. 实现call()方法,定义线程的执行逻辑,并返回一个结果。
3. 创建Callable接口的实现类的实例。
4. 使用FutureTask包装Callable实例。
5. 将FutureTask实例传递给Thread类的构造器,创建Thread对象。
6. 调用Thread对象的start()方法启动线程。
7. 通过FutureTask的get()方法获取任务的执行结果。
 

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
        return sum;
    }

    public static void main(String[] args) {
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread thread = new Thread(futureTask, "MyCallableThread");
        thread.start();

        try {
            Integer result = futureTask.get(); // 获取计算结果
            System.out.println("线程 " + Thread.currentThread().getName() + " 计算结果: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

线程的常用方法

1.start()
功能:启动线程,调用线程的run()方法。
示例:

     Thread thread = new Thread(() -> {
         System.out.println("线程运行中...");
     });
     thread.start();

2. run()
功能:线程的主体,包含线程要执行的代码。
示例:

  class MyThread extends Thread {
         @Override
         public void run() {
             System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
         }
     }

3. join()
功能:等待当前线程终止。可以带一个超时参数,表示等待的时间(以毫秒为单位)。
示例:

 Thread thread1 = new Thread(() -> {
         try {
             Thread.sleep(1000);
             System.out.println("线程1运行完毕");
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     });

     Thread thread2 = new Thread(() -> {
         try {
             thread1.join(); // 等待 thread1 完成
             System.out.println("线程2运行完毕");
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     });

     thread1.start();
     thread2.start();

4. sleep(long millis)
功能:使当前正在执行的线程暂停指定的时间(以毫秒为单位),进入阻塞状态。
示例:

 Thread thread = new Thread(() -> {
         try {
             System.out.println("线程开始睡眠");
             Thread.sleep(2000); // 暂停2秒
             System.out.println("线程睡眠结束");
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     });
     thread.start();

5. yield()
功能:让出CPU,允许其他线程执行。不保证当前线程会立即停止执行。
示例:

 Thread thread = new Thread(() -> {
         for (int i = 0; i < 5; i++) {
             System.out.println("线程运行中...");
             if (i == 2) {
                 Thread.yield(); // 让出CPU
             }
         }
     });
     thread.start();

6. isAlive()
功能:判断线程是否还活着(即是否已经完成执行)。
示例:

 Thread thread = new Thread(() -> {
         try {
             Thread.sleep(2000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     });
     thread.start();

     while (thread.isAlive()) {
         System.out.println("线程还在运行...");
         try {
             Thread.sleep(500);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     }
     System.out.println("线程已结束");

7. interrupt()
功能:中断线程。如果线程处于阻塞状态(如sleep或wait),会抛出InterruptedException。
示例:

Thread thread = new Thread(() -> {
         try {
             System.out.println("线程开始睡眠");
             Thread.sleep(5000); // 暂停5秒
             System.out.println("线程睡眠结束");
         } catch (InterruptedException e) {
             System.out.println("线程被中断");
         }
     });
     thread.start();

     try {
         Thread.sleep(1000); // 主线程暂停1秒
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
     thread.interrupt(); // 中断线程

8. getName()和setName(String name)
功能:获取和设置线程的名称。
示例:

Thread thread = new Thread(() -> {
         System.out.println("线程名称: " + Thread.currentThread().getName());
     }, "MyThread");
     thread.start();

9. getId()
功能:获取线程的唯一标识符。
示例:

 Thread thread = new Thread(() -> {
         System.out.println("线程ID: " + Thread.currentThread().getId());
     });
     thread.start();

10. getPriority()和setPriority(int priority)
功能:获取和设置线程的优先级。优先级范围是1到10,默认值是5。
示例:

 Thread thread = new Thread(() -> {
          System.out.println("线程优先级: " + Thread.currentThread().getPriority());
      });
      thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级
      thread.start();

11. isDaemon()和setDaemon(boolean on)
功能:获取和设置线程是否为守护线程。守护线程通常用于在后台执行一些服务,如垃圾回收。当所有非守护线程结束后,程序会自动退出。
示例:

 Thread thread = new Thread(() -> {
          while (true) {
              System.out.println("守护线程运行中...");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      });
      thread.setDaemon(true); // 设置为守护线程
      thread.start();

线程安全

在多线程环境中,多个线程可能会同时访问和修改共享资源,这可能导致数据不一致、死锁等问题。线程安全是指当多个线程访问某个类时,不管运行时环境如何调度这些线程,这个类的行为都能正确表现。确保线程安全的方法有很多,包括使用同步机制、不可变对象、原子类等。

线程安全的常见问题

数据竞争:多个线程同时读取和修改同一个变量,导致数据不一致。
死锁:两个或多个线程互相等待对方释放资源,导致所有线程都无法继续执行。
活锁:线程不断重复相同的操作,无法向前推进。
饥饿:某些线程因为长时间无法获得必要的资源而无法执行。

确保线程安全的方法

1. 同步机制

synchronized关键字
方法同步:在方法声明前加上synchronized关键字,确保同一时刻只有一个线程可以执行该方法。
代码块同步:在代码块前加上synchronized关键字,并指定一个对象作为锁,确保同一时刻只有一个线程可以执行该代码块。示例代码:

public class Counter {
    private int count = 0;

    // 方法同步
    public synchronized void increment() {
        count++;
    }

    // 代码块同步
    public void incrementWithBlock() {
        synchronized (this) {
            count++;
        }
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终计数: " + counter.getCount());
    }
}

ReentrantLock
提供了比synchronized更灵活的锁定操作,支持公平锁、非公平锁等。
需要手动获取和释放锁。示例代码:
 

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private int count = 0;
    private final Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终计数: " + counter.getCount());
    }
}

2. 不可变对象

不可变对象一旦创建后,其状态就不能改变。
常见的不可变对象有String、Integer等。示例代码:

public final class ImmutableClass {
    private final int value;

    public ImmutableClass(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        ImmutableClass obj = new ImmutableClass(10);

        Thread t1 = new Thread(() -> {
            System.out.println("线程1读取值: " + obj.getValue());
        });

        Thread t2 = new Thread(() -> {
            System.out.println("线程2读取值: " + obj.getValue());
        });

        t1.start();
        t2.start();
    }
}

3. 原子类

java.util.concurrent.atomic包提供了一些原子操作类,如AtomicInteger、AtomicLong等。
这些类提供了原子性的操作,确保在多线程环境下不会出现数据竞争。示例代码:

import java.util.concurrent.atomic.AtomicInteger;

public class Counter {
    private AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.incrementAndGet();
    }

    public int getCount() {
        return count.get();
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终计数: " + counter.getCount());
    }
}

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

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

相关文章

计算机毕业设计 基于Django的在线考试系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

[SAP ABAP] INCLUDE程序创建

在ABAP中&#xff0c;INCLUDE是一种结构化编程技术&#xff0c;它允许将一段程序代码片段包含到其他程序段中&#xff0c;以便复用和维护 INCLUDE程序创建的好处 ① 代码模块化 将常用的功能或通用的子程序存放到单独的文件中&#xff0c;使得主程序更简洁、易于理解和管理 ② …

一个为分布式环境设计的任务调度与重试平台,高灵活高效率,系统安全便捷,分布式重试杀器!(附源码)

背景 近日挖掘到一款名为“SnailJob”的分布式重试开源项目,它旨在解决微服务架构中常见的重试问题。在微服务大行其道的今天&#xff0c;我们经常需要对某个数据请求进行多次尝试。然而&#xff0c;当遇到网络不稳定、外部服务更新或下游服务负载过高等情况时&#xff0c;请求…

YOLO11改进|注意力机制篇|引入MSCA注意力机制

目录 一、【MSCA】注意力机制1.1【MSCA】注意力介绍1.2【MSCA】核心代码 二、添加【MSCA】注意力机制2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【MSCA】注意力机制 1.1【MSCA】注意力介绍 下图是【MSCA】的结构图&#xff0c;让我…

硬件SPI解析-基于江科大的源码

一、SPI基本介绍 SPI&#xff08;Serial Peripheral Interface&#xff09;通信协议是由摩托罗拉公司&#xff08;现为NXP Semiconductors的一部分&#xff09;在20世纪80年代中期开发的。SPI是一种同步串行通信接口&#xff0c;设计用于短距离通信&#xff0c;特别是嵌入式系统…

图片怎么转换成pdf格式?这5种转换方法一看就会

在工作学习中&#xff0c;PDF格式因其跨平台兼容性和安全性成为了工作和学习中不可或缺的文件格式。然而&#xff0c;很多时候我们需要将图片转换为PDF&#xff0c;以便更好地整理、分享和保存。今天&#xff0c;就为大家介绍5种高效的图片转PDF方法&#xff0c;一起来学习下吧…

让机器来洞察他的内心!

本文所涉及所有资源均在传知代码平台可获取。 目录 洞察你的内心&#xff1a;你真的这么认为吗&#xff1f; 一、研究背景 二、模型结构和代码 D. 不一致性学习网络 E. 多模态讽刺分类 三、数据集介绍 四、性能展示 五、实现过程 1. 下载预训练的 GloVe 词向量&#xff08;Comm…

端口被占用问题的解决方案

一、问题描述 如图&#xff0c;启动服务失败&#xff0c;失败原因是8080端口被占用 二、解决方案 1.更换端口为其它&#xff0c;例如8002 9001等 2.关闭占用端口的进程&#xff0c;推荐这种解决方案 步骤一&#xff1a;在win命令行查询占用该端口号的进程 命令如下 netsta…

使用浏览器这么多年,你真的了解DevTools吗?

Devtools是Web测试时每天都要用的工具&#xff0c;它提供了很多调试功能&#xff0c;可以帮助我们更好的定位问题。而我们平时使用的功能只是它全部功能的子集&#xff0c;很多功能并没用到过。 作为高频使用的工具&#xff0c;还是有必要好好掌握的。测试时在日常工作中提BUG…

项目前置知识

目录 std::bind 定时器 timerfd 时间轮设计 C11正则库 日志打印宏 通用类型ANY std::bind std::bind是C11提供的一个接口&#xff0c;他的功能&#xff1a;传递一个原始函数对象&#xff0c;对其绑定某些参数&#xff0c;生成一个新的函数对象。 其实简单来说&#xff…

YOLO--前置基础词-学习总结(上)

RFBNet是什么意思 RFBNet 是一种用于目标检测的深度学习网络&#xff0c;它的名字来源于 "Receptive Field Block Network"&#xff08;感受野块网络&#xff09;。简单来说&#xff0c;RFBNet 是一种可以让计算机更好地“看”图像中不同大小的物体的方法。 在图像处…

混凝土裂缝检测分割系统源码&数据集分享

混凝土裂缝检测分割系统源码&#xff06;数据集分享 [yolov8-seg-RCSOSA&#xff06;yolov8-seg-C2f-REPVGGOREPA等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Glo…

时间序列+Transformer席卷而来,性能秒杀传统,创新性拉满,引爆顶会!

时间序列分析与Transformer模型的结合&#xff0c;已成为深度学习领域的一大趋势。这种结合能够高效捕捉序列中的长期依赖关系&#xff0c;提升时间序列分析和预测的准确性。 时间序列Transformer技术在股票价格预测、气候预测、交通流量预测、设备故障预测、自然语言处理等多…

43页PPT | 大健康行业BI解决方案

药企应用现状与挑战 大健康行业中的药企在数据分析方面仍面临诸多挑战。传统的数据分析模式依赖于纸质记录和线下手动更新&#xff0c;导致数据时效性低、人力成本高&#xff0c;难以快速发挥数据价值。随着数据量的激增&#xff0c;多源数据的归集和整合成为药企数据分析的难点…

Python画笔案例-080 绘制 颜色亮度测试

1、绘制 颜色亮度测试 通过 python 的turtle 库绘制 颜色亮度测试,如下图: 2、实现代码 绘制 颜色亮度测试,以下为实现代码: """颜色亮度测试.py本程序需要coloradd模块支持,请在cmd窗口,即命令提示符下输入pip install coloradd进行安装。本程序演示brig…

JavaSE——面向对象6.1:继承知识点补充(虚方法表等)

目录 一、子类到底能继承父类中的哪些内容&#xff1f; 二、继承内存图 三、继承中&#xff1a;成员变量和成员方法的访问特点 (一)成员变量的访问特点 (二)成员方法的访问特点 1.this与super访问成员方法的特点 2.方法重写 2.1方法重写的本质&#xff1a;子类覆盖了从…

社区交流礼仪 | 提问的艺术

唠唠闲话 2021 年通过 Julia 社区了解到开源&#xff0c;自此开始融入开源社区&#xff0c;学习和体验这种独特的协作模式与交流文化&#xff0c;受益良多。本篇文章为开源新手必读&#xff0c;文章中探讨的交流模式&#xff0c;不仅对参与开源项目的协作有所帮助&#xff0c;…

计组体系软考题2-计算机组成原理与计算机体系结构概论

一、CPU组成&#xff08;运算器控制器&#xff09; 1.运算器 题1-存放操作数/运算结果的ACC累加寄存器 1. 2. 题2-加法器&#xff08;算术逻辑单元的部件&#xff09; 题3-判断对错 程序计数器PC&#xff08;运算器&#xff09;&#xff0c;只存放地址题4- 2. 控制器 题1-…

10.8每日作业

当用户点击取消按钮&#xff0c;弹出问题对话框&#xff0c;询问是否要确定退出登录&#xff0c;并提供两个按钮&#xff0c;yes|No&#xff0c;如果用户点击的Yes&#xff0c;则关闭对话框&#xff0c;如果用户点击的No&#xff0c;则继续登录 当用户点击的登录按钮&#xff…

热网无线监测系统 GetMenuItem 接口存在SQL注入漏洞

漏洞描述 热网无线监测系统 /DataSrvs/UCCGSrv.asmx/GetMenuItem 接口处存在SQL注入漏洞&#xff0c;未经身份验证的远程攻击者除了可以利用 SQL 注入漏洞获取数据库中的信息&#xff08;例如&#xff0c;管理员后台密码、站点的用户个人信息&#xff09;之外&#xff0c;甚至…