知了小站 - IT人的小站 https://www.ydyno.com/ zh-CN IT人的小站,分享开发经验,记录成长轨迹。 Thu, 29 Feb 2024 22:30:00 +0800 Thu, 29 Feb 2024 22:30:00 +0800 Java 模拟死锁以及如何避免死锁 https://www.ydyno.com/archives/1747.html https://www.ydyno.com/archives/1747.html Thu, 29 Feb 2024 22:30:00 +0800 知了小站 模拟死锁

死锁是多线程编程中常见的问题,它发生在两个或多个线程相互等待对方释放资源的情况下。以下是一个简单的Java死锁模拟示例:

public class DeadlockExample {

    public static void main(String[] args) {
        // 创建两个共享资源
        final Object resource1 = new Object();
        final Object resource2 = new Object();

        // 线程1尝试获取资源1,然后资源2
        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: Locked resource 1");

                try {
                    // 为了增加死锁的可能性,线程1休眠一段时间
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (resource2) {
                    System.out.println("Thread 1: Locked resource 2");
                }
            }
        });

        // 线程2尝试获取资源2,然后资源1
        Thread thread2 = new Thread(() -> {
            synchronized (resource2) {
                System.out.println("Thread 2: Locked resource 2");

                try {
                    // 为了增加死锁的可能性,线程2休眠一段时间
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (resource1) {
                    System.out.println("Thread 2: Locked resource 1");
                }
            }
        });

        // 启动线程1和线程2
        thread1.start();
        thread2.start();
    }
}

在这个例子中,两个线程分别尝试获取两个共享资源,但它们的获取顺序相反。如果这两个线程在不同的时刻开始执行,可能不会发生死锁,但如果它们同时开始执行,就有可能因为资源争夺而导致死锁。

如何避免死锁

避免死锁是多线程编程中非常重要的一个方面,以下是一些常见的避免死锁的策略:

  1. 锁的顺序:

    • 定义一个全局的锁获取顺序,然后在所有线程中都按照相同的顺序获取锁。这样可以避免不同线程以不同的顺序获取锁而导致死锁。
  2. 锁的超时机制:

    • 在获取锁的时候,设置一个超时机制。如果某个线程在一定时间内无法获取到所需的锁,就释放已经获取的锁,并重新尝试获取锁,或者执行其他逻辑来避免死锁。
  3. 使用 tryLock() 方法:

    • 在Java中,Lock 接口提供了 tryLock() 方法,它可以尝试获取锁,但不会一直等待。通过使用这个方法,你可以在获取锁失败时执行一些逻辑,而不是一直等待锁。
  4. 锁的粒度:

    • 设计时考虑锁的粒度。如果锁的范围太大,竞争会增加,容易导致死锁。将锁的范围缩小到最小必要范围,可以减少死锁的概率。
  5. 使用事务:

    • 在数据库操作中,使用事务可以避免某些类型的死锁。数据库事务通常会自动处理资源的锁定和释放。
  6. 死锁检测和处理:

    • 一些系统提供死锁检测机制,可以检测到死锁的发生,并采取一些措施,例如自动释放锁或终止某些线程。
  7. 避免循环等待:

    • 设定一个全局的资源获取顺序,并要求所有线程按照相同的顺序获取资源,以避免循环等待的情况。
  8. 使用高级同步工具:

    • Java提供了一些高级的同步工具,如 java.util.concurrent 包中的 ReentrantLockSemaphore 等,它们提供更灵活的控制和避免死锁的机制。

避免死锁是一个复杂的问题,需要在设计和实现阶段考虑。以上策略可以根据具体情况进行选择和组合,以提高多线程程序的稳定性。

]]>
0 https://www.ydyno.com/archives/1747.html#comments https://www.ydyno.com/feed/
Debian 10/11 安装最新版 Nginx https://www.ydyno.com/archives/1740.html https://www.ydyno.com/archives/1740.html Mon, 05 Jun 2023 14:16:00 +0800 知了小站 Debian 10 安装最新版的Nginx

要在Debian 10 上安装最新版的Nginx,可以使用以下步骤

1、更新系统

sudo apt update
sudo apt upgrade

2、添加 Nginx 的存储库密钥

wget http://nginx.org/keys/nginx_signing.key
sudo apt-key add nginx_signing.key

3、添加 Nginx 的存储库到apt源列表中

echo "deb http://nginx.org/packages/mainline/debian/ $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list

4、更新存储库并安装 Nginx

sudo apt update
sudo apt install nginx

# 启动 nginx
sudo systemctl start nginx
# 设置自启
sudo systemctl enable nginx

Debian 11 安装最新版的Nginx

在Debian 11 上安装最新版的Nginx,可以使用以下步骤

1、更新系统

sudo apt update
sudo apt upgrade
# 安装 Nginx 的依赖项
sudo apt install curl gnupg2 ca-certificates lsb-release

2、添加 Nginx 的存储库密钥

curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg

3、添加 Nginx 的存储库到apt源列表中

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/mainline/debian $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list

4、更新存储库并安装 Nginx

sudo apt update
sudo apt install nginx
# 启动 nginx
sudo systemctl start nginx
# 设置自启
sudo systemctl enable nginx
]]>
0 https://www.ydyno.com/archives/1740.html#comments https://www.ydyno.com/feed/
Jpa 持久层中使用自定义对象接收数据 https://www.ydyno.com/archives/1739.html https://www.ydyno.com/archives/1739.html Fri, 12 May 2023 16:32:00 +0800 知了小站 在 JPA 持久层中,可以自定义接收数据的对象。这通常用于查询操作,其中查询结果不完全匹配现有的实体类,或者需要仅返回某些字段的结果。以下示例,展示如何在 JPA 持久层中自定义接收数据的对象

假设有一个名为 Person 的实体类,包含 id、name 和 age 字段:

@Entity
@Table(name = "person")
public class Person {
  
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    private int age;
    
    // 省略构造函数、getter 和 setter 方法
}

现在我们只想查询人员的姓名和年龄,并将结果封装到自定义的数据对象 PersonInfo 中:

public class PersonInfo {
  
    private String name;
    
    private int age;
    
    // 省略构造函数、getter 和 setter 方法
}

第一种方式

@Repository
public class PersonRepository {
    @PersistenceContext
    private EntityManager entityManager;
    
    public List<PersonInfo> getPersonInfo() {
        String query = "SELECT new com.example.PersonInfo(p.name, p.age) FROM Person p";
        TypedQuery<PersonInfo> typedQuery = entityManager.createQuery(query, PersonInfo.class);
        return typedQuery.getResultList();
    }
}

在上面的代码中,我们使用 SELECT new 关键字创建了一个 PersonInfo 对象,并将查询结果映射到该对象。通过使用构造函数,可以选择性地指定要接收的字段。

第二种方式

使用 Spring Data JPA 的 Repository 接口

@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
    @Query("SELECT new com.example.PersonInfo(p.name, p.age) FROM Person p")
    List<PersonInfo> getPersonInfo();
}

在上面的示例中,我们使用了 @Query 注解,并指定了一个自定义的查询语句。在查询语句中,我们使用了 new 关键字创建了一个 PersonInfo 对象,并将查询结果映射到该对象。

注意点

在查询语句中,com.example.PersonInfo 是 PersonInfo 类的完全限定名,确保使用正确的包名,确保创建了对应的构造方法。

]]>
0 https://www.ydyno.com/archives/1739.html#comments https://www.ydyno.com/feed/
debian11 系统增加开机自启脚本 https://www.ydyno.com/archives/1736.html https://www.ydyno.com/archives/1736.html Fri, 21 Apr 2023 10:30:00 +0800 知了小站 在 debian11 系统增加开机自启脚本时发现 /etc 目录里面没有 rc.local 文件,导致无法添加自启动脚本,这里记录下 debian11 增加开机自启脚本的全过程。

修改 rc-local.service 文件

cd /lib/systemd/system

添加下面内容到 rc-local.service 文件最后

[Install]  
WantedBy=multi-user.target

创建 /etc/rc.local 文件

创建 /etc/rc.local 文件,并写入下面内容

#!/bin/sh -e

# 在这里输入需要自启的脚本
exit 0

创建完成后需要给其赋予运行权限

sudo chmod +x /etc/rc.local

启动 rc-local 服务即可

sudo systemctl enable rc-local  # 启用
sudo systemctl start rc-local.service # 开始运行
sudo systemctl status rc-local.service  # 查看状态
]]>
0 https://www.ydyno.com/archives/1736.html#comments https://www.ydyno.com/feed/
使用 qshell 工具上传文件夹到七牛云 https://www.ydyno.com/archives/1709.html https://www.ydyno.com/archives/1709.html Wed, 08 Mar 2023 15:32:00 +0800 知了小站 qshell 是利用七牛文档上公开的API实现的一个方便开发者测试和使用七牛API服务的命令行工具。下载地址: 直达 ,根据自己系统平台下载即可。

使用教程

下载后,随意放到哪都行。

1、赋予qshell执行权限

我这里是Linux系统,默认放到了 /root 目录,进入 /root 目录后赋予 qshell 执行权限

chmod +x qshell

2、配置七牛云账户

需要鉴权的命令都需要依赖七牛账号下的 AccessKeySecretKey点我直达 ,拿到 AccessKeySecretKey 输入下面的命令

./qshell account ak sk name

此处操作后在当前用户主目录中生成 qshell 目录:

ls ~/.qshell/
account.json

3、上传同步文件夹

./qshell qupload2 --src-dir=需要上传的文件夹 --bucket=对象存储桶的名称

更多使用方式:https://developer.qiniu.com/kodo/1302/qshell

]]>
0 https://www.ydyno.com/archives/1709.html#comments https://www.ydyno.com/feed/
Java 给 OkHttpClient 添加 Socks 代理 https://www.ydyno.com/archives/1708.html https://www.ydyno.com/archives/1708.html Mon, 06 Mar 2023 13:39:00 +0800 知了小站 OkHttpClient 我使用的并不多,这里记录下怎么给 OkHttpClient 添加代理,首先还是添加 OkHttpClient 依赖

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.10.0</version>
</dependency>

API接入

package demo;

import okhttp3.OkHttpClient;
import okhttp3.Request;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;


class ApiProxyJava {
    public static void main(String[] args) throws IOException {
        testHttpWithOkHttp();
        testSocks5WithOkHttp();
    }

    public static void testHttpWithOkHttp() throws IOException {
        String url = "https://www.google.com/";
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(IP, PORT));
        OkHttpClient client = new OkHttpClient().newBuilder().proxy(proxy).build();

        Request request = new Request.Builder().url(url).build();
        okhttp3.Response response = client.newCall(request).execute();
        String responseString = response.body().string();
        System.out.println(responseString);
        response.close();
    }

    public static void testSocks5WithOkHttp() throws IOException {
        String url = "https://www.google.com/";
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(IP, PORT));
        OkHttpClient client = new OkHttpClient().newBuilder().proxy(proxy).build();

        Request request = new Request.Builder().url(url).build();
        okhttp3.Response response = client.newCall(request).execute();
        String responseString = response.body().string();
        System.out.println(responseString);
        response.close();
    }

账密接入

package demo;

import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;

/**
 * compile 'com.squareup.okhttp3:okhttp:3.10.0'
 */
class AutProxyJava {
    public static void main(String[] args) throws IOException {
        testWithOkHttp();

        testSocks5WithOkHttp();
    }

    public static void testWithOkHttp() throws IOException {
        String url = "https://www.google.com/";
        String gateIp = ""
        int gatePort = 1000
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(gateIp, gatePort));
        OkHttpClient client = new OkHttpClient().newBuilder().proxy(proxy).proxyAuthenticator((route, response) -> {
            String credential = Credentials.basic("账户", "密码");
            return response.request().newBuilder()
                    .header("Proxy-Authorization", credential)
                    .build();
        }).build();


        Request request = new Request.Builder().url(url).build();
        okhttp3.Response response = client.newCall(request).execute();
        String responseString = response.body().string();
        System.out.println(responseString);
        response.close();
    }

    public static void testSocks5WithOkHttp() throws IOException {
         String url = "https://www.google.com/";
        String gateIp = ""
        int gatePort = 2000
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(gateIp, gatePort));
        java.net.Authenticator.setDefault(new java.net.Authenticator() {
            private PasswordAuthentication authentication =
                    new PasswordAuthentication("账户", "密码".toCharArray());

            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return authentication;
            }
        });
        OkHttpClient client = new OkHttpClient().newBuilder().proxy(proxy).build();
        
        Request request = new Request.Builder().url(url).build();
        okhttp3.Response response = client.newCall(request).execute();
        String responseString = response.body().string();
        System.out.println(responseString);
        response.close();
    }
}

原文地址:https://admin.rola-ip.co/v_manual.html#/api_java

]]>
0 https://www.ydyno.com/archives/1708.html#comments https://www.ydyno.com/feed/
Docker容器 - 数据打包迁移全过程记录 https://www.ydyno.com/archives/1704.html https://www.ydyno.com/archives/1704.html Thu, 23 Feb 2023 18:09:00 +0800 知了小站 记录下Docker容器打包迁移的一些命令:

# 确认要迁移容器的名称
docker ps -a
# 打包容器为新的镜像
docker commit 容器名 镜像名
# 把镜像保存为tar文件 
docker save 镜像名 >文件名称.tar
# 将文件传输到另一台服务器,用SCP命令
scp -P 22 /文件路径/文件名称.tar root@接收文件的服务器的IP:/存放文件的目录
# 恢复镜像
docker load < 文件名称.tar

恢复镜像后,用同样的方法创建容器即可。

]]>
0 https://www.ydyno.com/archives/1704.html#comments https://www.ydyno.com/feed/
Java 开发之 BigDecimal 用法细节详解 https://www.ydyno.com/archives/1700.html https://www.ydyno.com/archives/1700.html Thu, 01 Dec 2022 10:03:00 +0800 知了小站 一、BigDecimal 概述

​ Java 在 java.math 包中提供的 API 类 BigDecimal,用来对超过 16 位有效位的数进行精确的运算。双精度浮点型变量 double 可以处理 16 位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用 Float 和 Double 处理,但是 Double.valueOf(String) 和 Float.valueOf(String) 会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用 BigDecimal 类来操作。

​BigDecimal所创建的是对象,故我们不能使用传统的 +、-、*、/ 等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是 BigDecimal 的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

二、BigDecimal 常用构造函数

2.1、常用构造函数

// 创建一个具有参数所指定整数值的对象
BigDecimal(int)

// 创建一个具有参数所指定双精度值的对象
BigDecimal(double)

// 创建一个具有参数所指定长整数值的对象
BigDecimal(long)

// 创建一个具有参数所指定以字符串表示的数值的对象
BigDecimal(String)

2.2、使用问题分析

使用示例:

BigDecimal a =new BigDecimal(0.1);
System.out.println("a values is:"+a);
System.out.println("=====================");
BigDecimal b =new BigDecimal("0.1");
System.out.println("b values is:"+b);

结果示例:

a values is:0.1000000000000000055511151231257827021181583404541015625
=====================
b values is:0.1

原因分析:

1)参数类型为 double 的构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 newBigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

2)String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言, 通常建议优先使用String构造方法。

3)当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 构造方法,将 double 转换为 String。要获取该结果,请使用 static valueOf(double) 方法。

三、BigDecimal 常用方法详解

3.1、常用方法

// BigDecimal 对象中的值相加,返回 BigDecimal 对象
add(BigDecimal)

// BigDecimal 对象中的值相减,返回 BigDecimal 对象
subtract(BigDecimal)

// BigDecimal 对象中的值相乘,返回 BigDecimal 对象
multiply(BigDecimal)

// BigDecimal 对象中的值相除,返回 BigDecimal 对象
divide(BigDecimal)

// 将 BigDecimal 对象中的值转换成字符串
toString()

// 将 BigDecimal 对象中的值转换成双精度数
doubleValue()

// 将 BigDecimal 对象中的值转换成单精度数
floatValue()

// 将 BigDecimal 对象中的值转换成长整数
longValue()

// 将 BigDecimal 对象中的值转换成整数
intValue()

3.2、BigDecimal大小比较

java 中对 BigDecimal 比较大小一般用的是 bigdemical 的 compareTo 方法

int a = bigdemical.compareTo(bigdemical2)

返回结果分析:

a = -1,表示bigdemical小于bigdemical2;
a = 0,表示bigdemical等于bigdemical2;
a = 1,表示bigdemical大于bigdemical2;

举例:a大于等于b

new bigdemica(a).compareTo(new bigdemical(b)) >= 0

四、BigDecimal 格式化

由于 NumberFormat 类的 format() 方法可以使用 BigDecimal 对象作为其参数,可以利用 BigDecimal 对超出 16 位有效数字的货币值,百分值,以及一般数值进行格式化控制。

以利用 BigDecimal 对货币和百分比格式化为例。首先,创建 BigDecimal 对象,进行 BigDecimal 的算术运算后,分别建立对货币和百分比格式化的引用,最后利用 BigDecimal 对象作为 format() 方法的参数,输出其格式化的货币值和百分比。

NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用 
NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用 
percent.setMaximumFractionDigits(3); //百分比小数点最多3位 

BigDecimal loanAmount = new BigDecimal("15000.48"); //贷款金额
BigDecimal interestRate = new BigDecimal("0.008"); //利率   
BigDecimal interest = loanAmount.multiply(interestRate); //相乘

System.out.println("贷款金额:\t" + currency.format(loanAmount)); 
System.out.println("利率:\t" + percent.format(interestRate)); 
System.out.println("利息:\t" + currency.format(interest)); 

结果:

贷款金额: ¥15,000.48 利率: 0.8% 利息: ¥120.00

BigDecimal 格式化保留两位小数,不足则补 0:

public class NumberFormat {
    
    public static void main(String[] s){
        System.out.println(formatToNumber(new BigDecimal("3.435")));
        System.out.println(formatToNumber(new BigDecimal(0)));
        System.out.println(formatToNumber(new BigDecimal("0.00")));
        System.out.println(formatToNumber(new BigDecimal("0.001")));
        System.out.println(formatToNumber(new BigDecimal("0.006")));
        System.out.println(formatToNumber(new BigDecimal("0.206")));
    }
    /**
     * @desc 1.0~1之间的BigDecimal小数,格式化后失去前面的0,则前面直接加上0。
     * 2.传入的参数等于0,则直接返回字符串"0.00"
     * 3.大于1的小数,直接格式化返回字符串
     * @param obj传入的小数
     * @return
     */
    public static String formatToNumber(BigDecimal obj) {
        DecimalFormat df = new DecimalFormat("#.00");
        if(obj.compareTo(BigDecimal.ZERO)==0) {
            return "0.00";
        }else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){
            return "0"+df.format(obj).toString();
        }else {
            return df.format(obj).toString();
        }
    }
}

结果为:

3.44
0.00
0.00
0.00
0.01
0.21

五、BigDecimal常见异常

5.1、除法的时候出现异常

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result

原因分析:

​通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

解决方法:

​divide 方法设置精确的小数点,如:divide(xxxxx,2)

六、BigDecimal总结

6.1、总结

  1. 在需要精确的小数计算时再使用 BigDecimal,BigDecimal 的性能比 double 和 float 差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用 BigDecimal。
  2. 尽量使用参数类型为 String 的构造函数。
  3. BigDecimal 都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。

6.2、工具类推荐

package com.vivo.ars.util;
import java.math.BigDecimal;

/**
 * 用于高精确处理常用的数学运算
 */
public class ArithmeticUtils {
    //默认除法运算精度
    private static final int DEF_DIV_SCALE = 10;

    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */

    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static BigDecimal add(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2);
    }

    /**
     * 提供精确的加法运算
     *
     * @param v1    被加数
     * @param v2    加数
     * @param scale 保留scale 位小数
     * @return 两个参数的和
     */
    public static String add(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static BigDecimal sub(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2);
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1    被减数
     * @param v2    减数
     * @param scale 保留scale 位小数
     * @return 两个参数的差
     */
    public static String sub(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static BigDecimal mul(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2);
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1    被乘数
     * @param v2    乘数
     * @param scale 保留scale 位小数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2, int scale) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return round(b1.multiply(b2).doubleValue(), scale);
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1    被乘数
     * @param v2    乘数
     * @param scale 保留scale 位小数
     * @return 两个参数的积
     */
    public static String mul(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * 小数点以后10位,以后的数字四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */

    public static double div(double v1, double v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示需要精确到小数点以后几位
     * @return 两个参数的商
     */
    public static String div(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v1);
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static String round(String v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(v);
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 取余数
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 小数点后保留几位
     * @return 余数
     */
    public static String remainder(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 取余数  BigDecimal
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 小数点后保留几位
     * @return 余数
     */
    public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 比较大小
     *
     * @param v1 被比较数
     * @param v2 比较数
     * @return 如果v1 大于v2 则 返回true 否则false
     */
    public static boolean compare(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        int bj = b1.compareTo(b2);
        boolean res;
        if (bj > 0)
            res = true;
        else
            res = false;
        return res;
    }
}

原文地址:https://www.cnblogs.com/zhangyinhua/p/11545305.html

]]>
1 https://www.ydyno.com/archives/1700.html#comments https://www.ydyno.com/feed/
记 Docker 运行 Logstash out of memory 问题 https://www.ydyno.com/archives/1667.html https://www.ydyno.com/archives/1667.html Sat, 06 Aug 2022 15:50:00 +0800 知了小站 最近在 Docker 容器上搭建 Zookeeper+Kafka+Logstash+Elasticsearch+Kibana 日志分析系统,在运行 Logstash 和 Elasticsearch 时遇到了如下错误:

library initialization failed - unable to allocate file descriptor table - out of memorylibrary
initialization failed - unable to allocate file descriptor table - out of memory

l6hlzlt2.png

在这里记录下解决方案。

解决方案

通过重写 Docker 的 ExecStart 的参数解决

sudo systemctl edit docker

进入后,添加或者修改对应参数

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --default-ulimit nofile=65536:65536 -H fd://

最后重启 Docker

sudo systemctl daemon-reload
sudo systemctl restart docker

参考:https://stackoverflow.com/questions/68776387/docker-library-initialization-failed-unable-to-allocate-file-descriptor-tabl

]]>
0 https://www.ydyno.com/archives/1667.html#comments https://www.ydyno.com/feed/
ELADMIN 项目官网域名更换通知与加群答案 https://www.ydyno.com/archives/1646.html https://www.ydyno.com/archives/1646.html Tue, 02 Aug 2022 15:18:00 +0800 知了小站 为方便访问,已将 ELADMIN 官网域名更换为 eladmin.vip

访问老域名 el-admin.vip 会重定向到新域名 eladmin.vip

QQ交流群:891137268947578238659622532

入群答案:eladmin.vip

有关 ELADMIN 的更多问题访问

https://eladmin.vip/pages/020101/

]]>
1 https://www.ydyno.com/archives/1646.html#comments https://www.ydyno.com/feed/