sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://huecker.io",
"https://dockerhub.timeweb.cloud",
"https://noohub.ru"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
需要有一台国外服务器, 按下面添加 Nginx 配置即可,配置完成后,在 /etc/docker/daemon.json
中修改成你的域名,具体参考上方配置,然后重启 docker
server {
listen 443 ssl;
server_name 域名;
ssl_certificate 证书地址;
ssl_certificate_key 密钥地址;
proxy_ssl_server_name on; # 启用SNI
ssl_session_timeout 24h;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
location / {
proxy_pass https://registry-1.docker.io; # Docker Hub 的官方镜像仓库
proxy_set_header Host registry-1.docker.io;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 关闭缓存
proxy_buffering off;
# 转发认证相关的头部
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
# 对 upstream 状态码检查,实现 error_page 错误重定向
proxy_intercept_errors on;
# error_page 指令默认只检查了第一次后端返回的状态码,开启后可以跟随多次重定向。
recursive_error_pages on;
# 根据状态码执行对应操作,以下为301、302、307状态码都会触发
#error_page 301 302 307 = @handle_redirect;
error_page 429 = @handle_too_many_requests;
}
#处理重定向
location @handle_redirect {
resolver 1.1.1.1;
set $saved_redirect_location '$upstream_http_location';
proxy_pass $saved_redirect_location;
}
# 处理429错误
location @handle_too_many_requests {
proxy_set_header Host 替换为在CloudFlare Worker设置的域名; # 替换为另一个服务器的地址
proxy_pass http://替换为在CloudFlare Worker设置的域名;
proxy_set_header Host $http_host;
}
}
登录到 Cloudflare 控制台, 新建 worker, 在 worker.js 文件中输入以下代码, 注意需要自行修改代码中的域名
'use strict'
const hub_host = 'registry-1.docker.io'
const auth_url = 'https://auth.docker.io'
const workers_url = 'https://你的域名'
const workers_host = '你的域名'
const home_page_url = 'https://qninq.cn/file/html/dockerproxy.html'
/** @type {RequestInit} */
const PREFLIGHT_INIT = {
status: 204,
headers: new Headers({
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age': '1728000',
}),
}
/**
* @param {any} body
* @param {number} status
* @param {Object<string, string>} headers
*/
function makeRes(body, status = 200, headers = {}) {
headers['access-control-allow-origin'] = '*'
return new Response(body, {status, headers})
}
/**
* @param {string} urlStr
*/
function newUrl(urlStr) {
try {
return new URL(urlStr)
} catch (err) {
return null
}
}
addEventListener('fetch', e => {
const ret = fetchHandler(e)
.catch(err => makeRes('cfworker error:\n' + err.stack, 502))
e.respondWith(ret)
})
/**
* @param {FetchEvent} e
*/
async function fetchHandler(e) {
const getReqHeader = (key) => e.request.headers.get(key);
let url = new URL(e.request.url);
if (url.pathname === '/') {
// Fetch and return the home page HTML content with replacement
let response = await fetch(home_page_url);
let text = await response.text();
text = text.replace(/{workers_host}/g, workers_host);
return new Response(text, {
status: response.status,
headers: response.headers
});
}
if (url.pathname === '/token') {
let token_parameter = {
headers: {
'Host': 'auth.docker.io',
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
}
};
let token_url = auth_url + url.pathname + url.search
return fetch(new Request(token_url, e.request), token_parameter)
}
url.hostname = hub_host;
let parameter = {
headers: {
'Host': hub_host,
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
},
cacheTtl: 3600
};
if (e.request.headers.has("Authorization")) {
parameter.headers.Authorization = getReqHeader("Authorization");
}
let original_response = await fetch(new Request(url, e.request), parameter)
let original_response_clone = original_response.clone();
let original_text = original_response_clone.body;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;
if (new_response_headers.get("Www-Authenticate")) {
let auth = new_response_headers.get("Www-Authenticate");
let re = new RegExp(auth_url, 'g');
new_response_headers.set("Www-Authenticate", response_headers.get("Www-Authenticate").replace(re, workers_url));
}
if (new_response_headers.get("Location")) {
return httpHandler(e.request, new_response_headers.get("Location"))
}
let response = new Response(original_text, {
status,
headers: new_response_headers
})
return response;
}
/**
* @param {Request} req
* @param {string} pathname
*/
function httpHandler(req, pathname) {
const reqHdrRaw = req.headers
// preflight
if (req.method === 'OPTIONS' &&
reqHdrRaw.has('access-control-request-headers')
) {
return new Response(null, PREFLIGHT_INIT)
}
let rawLen = ''
const reqHdrNew = new Headers(reqHdrRaw)
const refer = reqHdrNew.get('referer')
let urlStr = pathname
const urlObj = newUrl(urlStr)
/** @type {RequestInit} */
const reqInit = {
method: req.method,
headers: reqHdrNew,
redirect: 'follow',
body: req.body
}
return proxy(urlObj, reqInit, rawLen, 0)
}
/**
*
* @param {URL} urlObj
* @param {RequestInit} reqInit
*/
async function proxy(urlObj, reqInit, rawLen) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)
// verify
if (rawLen) {
const newLen = resHdrOld.get('content-length') || ''
const badLen = (rawLen !== newLen)
if (badLen) {
return makeRes(res.body, 400, {
'--error': `bad len: ${newLen}, except: ${rawLen}`,
'access-control-expose-headers': '--error',
})
}
}
const status = res.status
resHdrNew.set('access-control-expose-headers', '*')
resHdrNew.set('access-control-allow-origin', '*')
resHdrNew.set('Cache-Control', 'max-age=1500')
resHdrNew.delete('content-security-policy')
resHdrNew.delete('content-security-policy-report-only')
resHdrNew.delete('clear-site-data')
return new Response(res.body, {
status,
headers: resHdrNew
})
}
部署完成后,点击设置->触发器->添加自定义域,绑定自己的域名即可。配置完成后,在 /etc/docker/daemon.json
中修改成你的域名,具体参考上方配置,然后重启 docker。
死锁是多线程编程中常见的问题,它发生在两个或多个线程相互等待对方释放资源的情况下。以下是一个简单的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();
}
}
在这个例子中,两个线程分别尝试获取两个共享资源,但它们的获取顺序相反。如果这两个线程在不同的时刻开始执行,可能不会发生死锁,但如果它们同时开始执行,就有可能因为资源争夺而导致死锁。
避免死锁是多线程编程中非常重要的一个方面,以下是一些常见的避免死锁的策略:
锁的顺序:
锁的超时机制:
使用 tryLock() 方法:
Lock
接口提供了 tryLock()
方法,它可以尝试获取锁,但不会一直等待。通过使用这个方法,你可以在获取锁失败时执行一些逻辑,而不是一直等待锁。锁的粒度:
使用事务:
死锁检测和处理:
避免循环等待:
使用高级同步工具:
java.util.concurrent
包中的 ReentrantLock
、Semaphore
等,它们提供更灵活的控制和避免死锁的机制。避免死锁是一个复杂的问题,需要在设计和实现阶段考虑。以上策略可以根据具体情况进行选择和组合,以提高多线程程序的稳定性。
]]>要在Debian 10 上安装最新版的Nginx,可以使用以下步骤
sudo apt update
sudo apt upgrade
wget http://nginx.org/keys/nginx_signing.key
sudo apt-key add nginx_signing.key
echo "deb http://nginx.org/packages/mainline/debian/ $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install nginx
# 启动 nginx
sudo systemctl start nginx
# 设置自启
sudo systemctl enable nginx
在Debian 11 上安装最新版的Nginx,可以使用以下步骤
sudo apt update
sudo apt upgrade
# 安装 Nginx 的依赖项
sudo apt install curl gnupg2 ca-certificates lsb-release
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
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
sudo apt update
sudo apt install nginx
# 启动 nginx
sudo systemctl start nginx
# 设置自启
sudo systemctl enable nginx
]]>假设有一个名为 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 类的完全限定名,确保使用正确的包名,确保创建了对应的构造方法。
]]>cd /lib/systemd/system
添加下面内容到 rc-local.service 文件最后
[Install]
WantedBy=multi-user.target
创建 /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 # 查看状态
]]>下载后,随意放到哪都行。
我这里是Linux系统,默认放到了 /root
目录,进入 /root
目录后赋予 qshell
执行权限
chmod +x qshell
需要鉴权的命令都需要依赖七牛账号下的 AccessKey
和 SecretKey
, 点我直达 ,拿到 AccessKey
和 SecretKey
输入下面的命令
./qshell account ak sk name
此处操作后在当前用户主目录中生成 qshell 目录:
ls ~/.qshell/
account.json
./qshell qupload2 --src-dir=需要上传的文件夹 --bucket=对象存储桶的名称
]]><dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
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();
}
}
]]># 确认要迁移容器的名称
docker ps -a
# 打包容器为新的镜像
docker commit 容器名 镜像名
# 把镜像保存为tar文件
docker save 镜像名 >文件名称.tar
# 将文件传输到另一台服务器,用SCP命令
scp -P 22 /文件路径/文件名称.tar root@接收文件的服务器的IP:/存放文件的目录
# 恢复镜像
docker load < 文件名称.tar
恢复镜像后,用同样的方法创建容器即可。
]]> Java 在 java.math 包中提供的 API 类 BigDecimal,用来对超过 16 位有效位的数进行精确的运算。双精度浮点型变量 double 可以处理 16 位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用 Float 和 Double 处理,但是 Double.valueOf(String) 和 Float.valueOf(String) 会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用 BigDecimal 类来操作。
BigDecimal所创建的是对象,故我们不能使用传统的 +、-、*、/
等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是 BigDecimal 的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
// 创建一个具有参数所指定整数值的对象
BigDecimal(int)
// 创建一个具有参数所指定双精度值的对象
BigDecimal(double)
// 创建一个具有参数所指定长整数值的对象
BigDecimal(long)
// 创建一个具有参数所指定以字符串表示的数值的对象
BigDecimal(String)
使用示例:
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 对象中的值相加,返回 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()
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
由于 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
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)
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;
}
}
]]>library initialization failed - unable to allocate file descriptor table - out of memorylibrary
initialization failed - unable to allocate file descriptor table - out of memory
在这里记录下解决方案。
通过重写 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
]]>