java必学必会之线程(2)

yizhihongxing

Java必学必会之线程(2)攻略

线程同步

在多线程编程中,线程同步是一个非常重要的问题。如果不加以控制,在多线程同时访问共享资源的情况下,可能会导致数据不一致、死锁等问题。

同步的两种方式

Java 中实现同步的两种方式分别是 synchronized 和 ReentrantLock。

synchronized 关键字是 Java 提供的默认的语言级别的同步机制,可以用于实现方法或者块的同步。当一个线程调用 synchronized 方法时,其他线程可以调用对象的非 synchronized 方法,但是会阻塞,直到第一个线程执行完毕。

public synchronized void deposit(int amount) {  
    balance = balance + amount;  
}

ReentrantLock 则是 Java 提供的高级同步机制,可以更加灵活地对锁进行控制。与 synchronized 相比,ReentrantLock 支持更加灵活的同步方式,如公平锁、多个 Condition 等。

Lock lock = new ReentrantLock();  
...  
lock.lock();  
try {
    // 内部业务逻辑  
} finally {  
    lock.unlock();  
}

死锁的产生

在多线程编程中,死锁是常见的难题。死锁是指两个或多个线程在执行过程中,因竞争资源或互相等待而造成的一种互相等待的现象。

死锁原因通常有以下几种:

  • 竞争资源
  • 线程锁定顺序死锁
  • 动态的锁顺序死锁

以下示例说明了死锁的问题:

class DeliveryService{
    public synchronized void takeOrder(Order order){
        // 待实现的代码
    }
    public synchronized void deliverOrder(Order order){
        // 待实现的代码
    }
}

在上述示例代码中,当一个派送员在派送订单时,需要先占用 deliverOrder 方法的锁。而这个派送员在派送订单前,需要先接受顾客的订单,也就是占用 takeOrder 方法的锁。如果此时多个派送员同时接收订单,那么就会发生死锁。

避免死锁

避免死锁问题,一种方法是通过共享锁来实现同步。另外,还需要注意避免锁竞争、锁嵌套等问题。

以下是一些避免死锁的方法:

  • 破坏请求资源的环路
  • 使用尝试锁定机制
  • 按顺序加锁
  • 应用程序拥有锁的时长尽可能短

线程的池化

线程池是 Java 并发包提供的用于管理线程的工具。线程池由线程池管理器和一组工作线程组成。

如何使用线程池

int corePoolSize = 5;// 池中所保存的线程数,包括空闲线程。   
int maximumPoolSize = 10;// 池中允许的最大线程数。  
long keepAliveTime = 60000;// 当线程数大于核心线程数时,此为终止多余的空闲线程等待新任务的最长时间。     
BlockingQueue workQueue = new LinkedBlockingQueue();// 当线程池的任务队列满时,提交的任务将在此队列中等待。 
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,TimeUnit.MILLISECONDS, workQueue);
threadPool.execute(new MyTask());// 调用execute方法添加一个要执行的任务
threadPool.shutdown();// 当添加任务后关闭线程池

线程池任务队列的选择

Java 中线程池任务队列的选择有以下几种:

  • LinkedBlockingQueue:基于链表的阻塞队列,按照先进先出的原则对任务进行排序。适用于任务比较频繁且任务处理时间比较短的情况。
  • ArrayBlockingQueue:基于数组的有界队列,适用于任务比较稳定的情况。
  • PriorityBlockingQueue:具有优先级的无界队列。

示例

同步示例

以下示例代码演示了使用 synchronize 关键字实现同步。

public class Counter {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
    public synchronized void decrement() {
        count--;
    }
    public synchronized int getCount() {
        return count;
    }
}

public class Worker extends Thread {
    private Counter counter;
    public Worker(Counter counter) {
        this.counter = counter;
    }
    public void run() {
        for (int i = 0; i < 1000000; i++) {
            counter.increment();
            counter.decrement();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Worker[] workers = new Worker[10];
        for (int i = 0; i < 10; i++) {
            workers[i] = new Worker(counter);
            workers[i].start();
        }
        for (int i = 0; i < 10; i++) {
            try {
                workers[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(counter.getCount());
    }
}

线程池示例

以下示例代码演示了使用线程池的方式执行任务。

public class TestThreadPool {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            threadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}

以上线程池中的任务将交给线程池中的工作线程执行,当全部任务执行完毕后,线程池会自动关闭。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java必学必会之线程(2) - Python技术站

(0)
上一篇 2023年5月30日
下一篇 2023年5月30日

相关文章

  • bootstrap 下拉多选框进行多选传值问题代码分析

    下面给出“bootstrap下拉多选框进行多选传值问题代码分析”的完整攻略。 1. 背景 在使用bootstrap开发Web应用时,经常会使用下拉多选框进行多选,但如何将所选的值传递给后端服务器,还是一个值得探讨的问题。 2. 问题 bootstrap的下拉多选框有一个data-selected-text-format属性,它可以控制选中的值的格式,如可以将…

    Java 2023年6月15日
    00
  • javascript设计模式 – 组合模式原理与应用实例分析

    下面是本文“javascript设计模式 – 组合模式原理与应用实例分析”的完整攻略。 概述 组合模式是一种结构型设计模式,它将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性,用户无需关心所使用对象的具体类型,只需要关心对象之间的层次关系。 模式结构 组合模式包含以下角色:- Component(抽象构…

    Java 2023年5月26日
    00
  • SpringBoot拦截器使用精讲

    Spring Boot拦截器使用精讲 拦截器是一种常用的技术,可以在请求到达控制器之前或之后执行一些操作。在Spring Boot中,可以使用拦截器来实现一些常见的功能,例如身份验证、日志记录、性能监控等。本文将深入讲解Spring Boot拦截器的使用,包括拦截器的定义、注册和使用,以及两个示例。 定义拦截器 在Spring Boot中,可以通过实现Han…

    Java 2023年5月15日
    00
  • Jenkins一键打包部署SpringBoot应用

    针对“Jenkins一键打包部署SpringBoot应用”的完整攻略,我将从以下几个方面进行详细讲解: 前置条件 在使用Jenkins进行一键打包部署SpringBoot应用之前,我们需要进行一些准备工作,包括: 安装好Jenkins 在Jenkins中安装好“Pipeline”和“Git”插件 在本地安装好Git工具 保证环境中已经正确配置好了Java开发…

    Java 2023年5月19日
    00
  • Springboot开发OAuth2认证授权与资源服务器操作

    Spring Boot开发OAuth2认证授权与资源服务器操作 OAuth2认证授权是Web开发中非常实用的技术,解决了多种应用程序认证和权限的问题。在Spring Boot中集成OAuth2是一个非常流行的做法,本文将讲解如何使用Spring Boot来实现OAuth2认证和授权。 步骤 步骤1:创建Spring Boot项目 首先我们要创建一个Sprin…

    Java 2023年5月20日
    00
  • hibernate增删改查操作代码

    下面我将详细讲解 Hibernate 的增删改查操作代码的完整攻略。 首先,使用 Hibernate 进行增删改查操作需要遵循以下步骤: 配置 Hibernate 配置文件 hibernate.cfg.xml 创建 Hibernate 工厂对象 SessionFactory 创建 Session 对象 开启事务 执行相应的增删改查操作 提交事务 关闭 Ses…

    Java 2023年5月19日
    00
  • SpringData JPA的常用语法汇总

    下面将详细讲解关于Spring Data JPA的常用语法汇总。 一、什么是Spring Data JPA Spring Data JPA是Spring框架的一个扩展模块,可以使用简单且统一的API,提供了CRUD操作,还支持基于方法名称的查询、@Query查询以及Specification查询等。它更加注重与实体类相关的持久化层操作,将封装JPA的强大功能…

    Java 2023年6月2日
    00
  • Java生成和解析XML格式文件和字符串的实例代码

    下面我将详细讲解“Java生成和解析XML格式文件和字符串的实例代码”的完整攻略以及其中的两个示例。 1. 什么是XML XML是可扩展标记语言(Extensible Markup Language)的缩写,它是一种用于传输和存储数据的标准格式。XML是自我描述、可扩展的,可以通过文本编辑器或工具生成并解析。在Java应用程序中,XML是一种常见的数据交换格…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部