java——多线程

news2025/1/4 19:54:25

文章目录

  • Java 的并发基础知识
    • 1. 创建线程
    • 2. 同步方法和同步代码块
    • 3. 线程安全的容器
    • 4. volatile 关键字
    • 5. Lock 和 Condition 接口
  • Java 多线程编程的基本框架
    • 1. 创建和启动线程
    • 2. 线程的状态转换
    • 3. 线程安全
    • 4. 死锁
  • Java 并发编程的高级技术
    • 1. 线程池
    • 2. 并发集合
    • 3. 原子类
    • 4. 锁

在这里插入图片描述

Java 的并发基础知识

了解什么是线程、进程、多线程并发等概念,掌握 Java 中的 synchronized 和 volatile 关键字以及 Lock 和 Condition 接口等重要的并发工具。

下面是 Java 中并发基础知识的代码示例:

1. 创建线程

Java 中有两种方式来创建线程,一种是继承 Thread 类,另一种是实现 Runnable 接口。下面是使用继承 Thread 类的方式来创建线程的示例代码:

public class MyThread extends Thread {
    public void run() {
        System.out.println("MyThread is running...");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

2. 同步方法和同步代码块

在多个线程同时访问共享资源时,需要对这些资源进行同步,以避免数据不一致或者数据污染等问题。Java 中提供了 synchronized 关键字来实现同步,可以用于修饰方法和代码块。下面是使用 synchronized 修饰方法和代码块的示例代码:

public class Counter {
    private int count = 0;

    // 使用 synchronized 修饰方法
    public synchronized void increment() {
        count++;
    }

    // 使用 synchronized 修饰代码块
    public void decrement() {
        synchronized (this) {
            count--;
        }
    }

    public int getCount() {
        return count;
    }
}

3. 线程安全的容器

Java 中提供了一些线程安全的容器类,比如 Vector、Hashtable 和 Collections.synchronizedXXX 等。这些容器类可以保证在多个线程同时访问容器时,不会出现数据不一致或者数据污染等问题。下面是使用 Vector 来实现线程安全的并发队列的示例代码:

public class ConcurrentQueue {
    private Vector<String> queue = new Vector<>();

    public void enqueue(String element) {
        queue.add(element);
    }

    public String dequeue() {
        if (queue.isEmpty()) {
            return null;
        } else {
            return queue.remove(0);
        }
    }
}

4. volatile 关键字

volatile 关键字用于标记变量为“易失性变量”,即该变量可能被多个线程同时修改和访问,从而确保多个线程之间对该变量的可见性。下面是使用 volatile 修饰变量的示例代码:

public class MyThread extends Thread {
    private volatile boolean running = true;

    public void run() {
        while (running) {
            // do something here
        }
    }

    public void shutdown() {
        running = false;
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();

        // 让主线程休眠一段时间后,停止子线程
        Thread.sleep(1000);
        thread.shutdown();
    }
}

5. Lock 和 Condition 接口

Lock 和 Condition 接口是 Java 中提供的可重入锁和条件变量,用于实现更灵活的线程同步控制。下面是使用 Lock 和 Condition 接口来实现线程同步的示例代码:

public class Buffer {
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
    private List<Integer> list = new ArrayList<>();
    private int capacity;

    public Buffer(int capacity) {
        this.capacity = capacity;
    }

    public void put(int element) throws InterruptedException {
        lock.lock();
        try {
            while (list.size() == capacity) {
                notFull.await();
            }

            list.add(element);
            notEmpty.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public int get() throws InterruptedException {
        lock.lock();
        try {
            while (list.size() == 0) {
                notEmpty.await();
            }

            int element = list.remove(0);
            notFull.signalAll();
            return element;
        } finally {
            lock.unlock();
        }
    }
}

以上是 Java 中并发基础知识的相关示例代码。需要注意的是,在实际开发中,多线程程序的正确性和稳定性非常重要。在编写多线程程序时,应该尽可能地避免竞态条件、死锁、饥饿和活锁等问题,并且合理地控制线程的数量和优先级,以保证多线程程序的正确运行。

此外,在实际开发中,可以使用一些辅助工具来帮助我们调试和排查多线程程序中的问题,比如 Java VisualVM、jstack、jmap、jcmd 等。

总之,学习 Java 的并发基础知识只是掌握多线程编程的第一步,需要不断地实践和探索,提高自己的多线程编程能力,才能写出高效、健壮的应用程序。

Java 多线程编程的基本框架

包括创建和启动线程、线程的状态转换、线程安全和死锁等基本概念。
下面是使用 Java 多线程编程基本框架的示例代码:

1. 创建和启动线程

Java 中有两种方式来创建线程,一种是继承 Thread 类,另一种是实现 Runnable 接口。下面是使用继承 Thread 类的方式来创建和启动线程的示例代码:

public class MyThread extends Thread {
    public void run() {
        System.out.println("MyThread is running...");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

2. 线程的状态转换

Java 中的线程有以下几种状态,可以通过 getState() 方法获取线程的状态:

  • NEW:新建状态,表示线程已经被创建但还没有调用 start() 方法;
  • RUNNABLE:运行状态,表示线程正在执行或者等待 CPU 时间片;
  • BLOCKED:阻塞状态,表示线程正在等待某个事件发生,如输入输出操作或 synchronized 代码块的监视器锁;
  • WAITING:等待状态,表示线程正在等待另一个线程通知或唤醒它;
  • TIMED_WAITING:计时等待状态,表示线程正在执行 sleep()、wait(long) 或 join(long) 方法;
  • TERMINATED:死亡状态,表示线程已经完成了它的任务,或者发生了异常而导致线程终止。

下面是使用 getState() 方法获取线程状态的示例代码:

public class MyThread extends Thread {
    public void run() {
        System.out.println("MyThread is running...");
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        System.out.println(thread.getState()); // NEW
        thread.start();
        System.out.println(thread.getState()); // RUNNABLE
        Thread.sleep(1000);
        System.out.println(thread.getState()); // TERMINATED
    }
}

3. 线程安全

在多个线程同时访问共享资源时,可能会出现数据不一致或者数据污染等问题。Java 中提供了 synchronized 关键字来实现同步,可以用于修饰方法和代码块。使用 synchronized 可以确保多个线程不会同时执行同一个方法或代码块,从而保证了线程安全。下面是使用 synchronized 实现线程安全的计数器的示例代码:

public class Counter {
    private int count = 0;

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

    public synchronized void decrement() {
        count--;
    }

    public synchronized int getCount() {
        return count;
    }
}

4. 死锁

死锁是指两个或多个线程都在等待对方释放资源,永久阻塞的情况。在多线程编程中,为了避免死锁问题,应该尽量避免线程间的循环依赖和资源竞争。下面是模拟死锁的示例代码:

public class DeadLockDemo {
    private static Object lock1 = new Object();
    private static Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread1 acquired lock1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("Thread1 acquired lock2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread2 acquired lock2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("Thread2 acquired lock1");
                }
            }
        });

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

以上是使用 Java 多线程编程基本框架的相关示例代码。需要注意的是在实际开发中,需要谨慎地使用多线程编程,特别是对于涉及到共享资源的场景。以下是一些注意事项:

  1. 避免竞态条件

竞态条件是指多个线程访问共享资源时,由于执行顺序不确定而导致结果不确定的情况。可以通过 synchronized 关键字或者 Lock 接口来解决竞态条件问题。

  1. 避免死锁

死锁是指两个或多个线程都在等待对方释放资源,永久阻塞的情况。可以通过避免循环依赖和资源竞争来避免死锁问题。

  1. 谨慎使用 Thread.sleep()

Thread.sleep() 方法会使当前线程休眠一段时间,但它并不会释放对象监视器锁。因此,在多线程编程中,应该谨慎使用 Thread.sleep() 方法,避免出现死锁等问题。

  1. 使用 Executor 框架

Executor 是一个用于管理和执行线程的框架,它提供了更加灵活的线程池机制和任务队列,能够有效地管理和调度线程,避免线程数量过多或过少的问题。

  1. 使用 volatile 关键字

volatile 关键字可以保证变量在多个线程之间的可见性和有序性,可以避免由于线程之间不同步而导致的数据不一致问题。但是,它并不能保证原子性和互斥性,需要慎重使用。

总之,在多线程编程中,需要特别注意线程安全、死锁、性能等问题,并采用合适的方式来解决这些问题,才能写出高效、健壮的应用程序。

Java 并发编程的高级技术

如线程池、线程同步、阻塞队列、Callable 和 Future 等。
Java 并发编程的高级技术包括线程池、并发集合、原子类和锁等。下面对这些技术进行详细解释,并给出相应的示例代码:

1. 线程池

线程池是一个用于管理和调度线程的工具,它可以有效地控制线程的数量和优先级,提高多线程程序的性能和稳定性。在 Java 中,线程池主要有以下几种类型:

  • FixedThreadPool:固定大小的线程池,适合处理执行时间较短的任务;
  • CachedThreadPool:无限大小的线程池,适合处理执行时间较长的任务;
  • ScheduledThreadPool:固定大小的线程池,适合周期性地执行任务;
  • SingleThreadExecutor:单个线程的线程池,适合按顺序执行任务。

下面是使用 FixedThreadPool 创建线程池并执行任务的示例代码:

public class MyTask implements Runnable {
    private String name;

    public MyTask(String name) {
        this.name = name;
    }

    public void run() {
        System.out.println(name + " is running...");
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 5; i++) {
            executor.execute(new MyTask("Task" + i));
        }
        executor.shutdown();
        while (!executor.isTerminated()) {
            Thread.sleep(1000);
        }
        System.out.println("All tasks have been executed.");
    }
}

2. 并发集合

并发集合是一种线程安全的容器,可以在多个线程同时访问时保证数据的一致性和正确性。Java 中提供了一些并发集合类,包括 ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentLinkedQueue 等。下面是使用 ConcurrentHashMap 实现线程安全的计数器的示例代码:

public class Counter {
    private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

    public void increment(String key) {
        map.compute(key, (k, v) -> v == null ? 1 : v + 1);
    }

    public void decrement(String key) {
        map.compute(key, (k, v) -> v == null ? -1 : v - 1);
    }

    public int getCount(String key) {
        return map.getOrDefault(key, 0);
    }
}

3. 原子类

原子类是一种线程安全的、不可分割的操作,可以保证对数值型变量的读取和修改操作都是原子性的。Java 中提供了一些原子类,包括 AtomicInteger、AtomicLong、AtomicBoolean 等。下面是使用 AtomicInteger 实现线程安全的计数器的示例代码:

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

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

    public void decrement() {
        count.decrementAndGet();
    }

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

4. 锁

锁是一种用于控制多个线程对共享资源的访问的机制,可以保证同一时间只有一个线程可以访问共享资源。Java 中提供了 synchronized 关键字和 Lock 接口两种实现锁的方式。下面是使用 synchronized 实现锁的示例代码:

public class Counter {
    private int count = 0;
    private Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public void decrement() {
        synchronized (lock) {
            count--;
        }
    }

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

以上是 Java 并发编程的高级技术及相关示例代码。在实际开发中,需要根据具体需求选择合适的技术来提高程序的性能和稳定性,并注意线程安全、死锁等问题。以下是一些注意事项:

  1. 避免锁竞争

在多线程编程中,锁的性能占据了很大一部分,因此需要尽量避免锁竞争。可以使用无锁算法、分段锁、读写锁等方式来减少锁竞争。

  1. 减少上下文切换

上下文切换是指操作系统将当前执行状态保存下来,然后切换到另一个线程或进程的执行状态的过程,会消耗额外的时间和资源。为了减少上下文切换,可以采用合适的线程数量、调整任务大小等方式。

  1. 谨慎使用 ThreadLocal

ThreadLocal 是一种线程本地变量,每个线程都有自己的副本,可以避免多线程访问时出现数据共享和污染的问题。但是,如果使用不当,会导致内存泄露等问题。

  1. 使用 ForkJoin 框架

ForkJoin 是一个用于并行计算的框架,它采用工作窃取算法来解决任务负载不均衡的问题,可以很好地提高程序的并发性能。

总之,在 Java 并发编程的高级技术中,需要注意锁竞争、上下文切换、ThreadLocal 的使用和并发集合的选择等问题,采用合适的技术来解决这些问题。

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

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

相关文章

测试:进阶篇

在本篇章开始之前&#xff0c;先对之前的内容进行一个简单的总结回顾一下&#xff1a; 基于需求设计测试用例&#xff0c;这里有个测试用例的万能公式&#xff1a; 功能&#xff08;如果是软件&#xff0c;需要参考依据需求规格说明书&#xff1b;如果是物体&#xff0c;这个…

2023年7月电脑选择

文章目录 一、笔记本1.1 确定需求1.2 确定预算1.3 性能指标1.4 其他 二、台式电脑 最近有朋友让我推荐一下能做3D建模的笔记本电脑&#xff0c;本文就讲一下台式机和笔记本怎么选择。 一、笔记本 1.1 确定需求 当我们在选择笔记本时&#xff0c;首先需要确定自己的需求&#x…

CSS基础学习--24 表单

一、一个表单案例&#xff0c;我们使用 CSS 来渲染 HTML 的表单元素 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>CSS基础学习-表单</title> </head> <style> input[typetext], select {width:…

计算机基础--->数据结构(3)【堆(超详细)】

文章目录 堆堆的时间复杂度堆的分类堆的存储堆的操作插入元素删除堆顶元素 堆排序建堆排序 所有操作代码 堆 堆一般分为两种类型&#xff1a;最大堆和最小堆。在最大堆中&#xff0c;父节点的值总是大于或等于子节点的值&#xff0c;而在最小堆中&#xff0c;父节点的值总是小于…

计算机自我介绍500字范文(合集)

计算机自我介绍500字范文1 本人是___大学计算机系统维护专业的学生。大学四年的学习&#xff0c;积累了丰富的专业知识&#xff0c;广泛的人际关系&#xff0c;培养我成为一个敢于承担责任&#xff0c;对待生活乐观积极&#xff0c;吃苦耐劳的青年。在专业方面我的主攻方向是计…

Ffmpeg6.0版本源码解读第一期!

前言&#xff1a; 大家好&#xff0c;最近一直在直播讲解Ffmpeg6.0版本的源码解析&#xff0c;这里要明白学习源码能给我们带来什么好处&#xff1f;我相信很多小伙伴已经用过Ffmpeg去开发&#xff0c;不知道大家有没有在开发的过程&#xff0c;调用接口的时候&#xff0c;是否…

PowerDesigner面向对象建模-常用UML图

1 PowerDesigner简介 PowerDesigner最初由Xiao-Yun Wang&#xff08;王晓昀&#xff09;在SDP Technologies公司开发完成。PowerDesigner是Sybase的企业建模和设计解决方案&#xff0c;采用模型驱动方法&#xff0c;将业务与IT结合起来&#xff0c;可帮助部署有效的企业体系架…

python熟悉python基础语法,了解html网络结构,了解json格式数据,含有字符串

前言 Python网络爬虫是利用Python编写的程序&#xff0c;通过自动化地访问网页、解析html或json数据&#xff0c;并提取所需信息的技术。下面将详细介绍一些与Python网络爬虫相关的重要知识点。 1、Python基础语法&#xff1a; 变量和数据类型&#xff1a;学习如何声明变量以及…

使用R语言绘制富集条形图,轻松分析基因表达数据

一、引言 富集分析&#xff08;enrichment analysis&#xff09;是一种生物信息学方法&#xff0c;它可以帮助我们识别基因或其他的生物实体在某个特定的类别中过度表示的趋势。通俗来说&#xff0c;富集分析通过将基因分类到特定的集合中&#xff0c;然后根据基因在集合中的分…

万字长文带你深入理解JavaNIO并手动实现多人聊天室

NIO 网络编程 代码已同步至GitCode&#xff1a;https://gitcode.net/ruozhuliufeng/java-project.git Java NIO简介 IO概述 ​ IO的操作方式通常分为几种&#xff1a;同步阻塞BIO、同步非阻塞NIO、异步非阻塞AIO。 ​ &#xff08;1&#xff09;在JDK1.4之前&#xff0c;我们…

哈希表/散列表(HashTable)c++实现

目录 哈希表实现的思想 除留余数法 哈希冲突 第一种方法&#xff1a;探测法实现哈希表 探测法的思想 结点类 插入数据(insert) 冲突因子 数据扩容 哈希值 插入的代码实现以及哈希类 查找数据(find) 删除数据(erase) 第二种方法&#xff1a;拉链法实现哈希表 …

Kotlin~迭代器模式

概念 提供一种遍历集合元素的方法&#xff0c;而不暴露集合内部的实现。 角色介绍 iterator 迭代器接口: 定义访问和遍历集合元素的接口&#xff0c;一般包含next和hasNext方法。concrete iterator 具体迭代器: 实现迭代器接口&#xff0c;迭代器的核心逻辑实现。aggregate …

极致呈现系列之:Echarts热力图的神奇光晕

目录 什么是热力图热力图的特性及应用场景热力图的特性热力图的应用场景 Echarts中热力图的常用属性vue3中创建热力图 什么是热力图 热力图&#xff08;Heatmap&#xff09;是一种基于颜色映射的数据可视化图表&#xff0c;用于展示数据点的密度和分布情况。它使用不同的颜色强…

RT-Thread-10-线程优先级翻转

线程优先级翻转 前面讲到信号量和互斥量&#xff0c;二者有些区别&#xff1a; 信号量&#xff0c;可以在任何线程&#xff08;以及中断&#xff09;释放&#xff0c;用于同步&#xff0c;线程只在获得许可时才可以运行&#xff0c;强调的是运行步骤&#xff1b; 互斥量&#…

科技项目验收测试规范有哪些?

随着科技的不断发展和进步&#xff0c;越来越多的科技项目被投入使用。为了保证这些科技项目的质量&#xff0c;需要进行验收测试。科技项目验收测试是一项非常重要的工作&#xff0c;其结果对项目的质量和功能正常使用有着直接的影响。本文将就科技项 目验收测试规范和第三方软…

基于51单片机设计的公交车LED屏

一、项目介绍 为了提高公交车站点信息的实时性和准确性,方便乘客及时了解公交车到站信息,从而提高公交出行的便利性和舒适度。传统的公交车到站信息是通过人工喊话或者静态的站牌来实现的,这种方式存在信息不及时、不准确、不方便等问题。当前设计基于STC89C52单片机和MAX7…

PyQt6中文手册

PyQt6中文手册 一、PyQt6 简介 最后更新于 2021.04.22 本教程是 PyQt6 的入门教程。本教程的目的是让您开始使用 PyQt6 库。 关于 PyQt6 PyQt6 Digia 公司的 Qt 程序的 Python 中间件。Qt库是最强大的GUI库之一。PyQt6的官网&#xff1a;www.riverbankcomputing.co.uk/new…

2023年企业应该关注的10种AI攻击类型

2023年&#xff0c;热度很高的一个话题莫不是生成式AI和chat GPT了。但是&#xff0c;人工智能&#xff08;AI&#xff09;技术的应用安全威胁都已经开始显现。安全研究人员表示&#xff0c;在AI技术快速应用发展过程中&#xff0c;其安全性也面临诸多挑战。为了防范AI技术大规…

【C++】哈希unordered系列容器的模拟实现

文章目录 一、哈希表的模拟实现&#xff08;开散列&#xff09;1. 开散列的概念2. 开散列的节点结构3. 开散列的插入删除与查找4. 开散列整体代码实现 二、unordered系列容器的封装实现(开散列)1. 迭代器2. unordered_set和unordered_map的封装实现3. 哈希表整体源码 一、哈希表…

Jacoco代码覆盖率测试

​欢迎光临我的博客查看最新文章: https://river106.cn 1、简介 JaCoCo(Java Code Coverage)是一个开源的覆盖率工具&#xff0c;它针对的开发语言是java&#xff0c;其使用方法很灵活&#xff0c;可以嵌入到Ant、Maven中。 很多第三方的工具提供了对JaCoCo的集成&#xff0c;…