import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SynchronizedArrayListExample {
public static void main(String[] args) {
// 创建一个线程安全的 ArrayList
List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<>());
// 创建并启动多个线程同时向 ArrayList 中添加元素
for (int i = 0; i < 5; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
synchronized (synchronizedList) {
synchronizedList.add(j);
}
}
}).start();
}
// 等待所有线程执行完毕
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出 ArrayList 中的元素个数
System.out.println("Size of synchronized ArrayList: " + synchronizedList.size());
}
}
在高并发的情况下,多个线程同时操作 ArrayList 可能会引发线程不安全的问题,主要有以下几个原因:
为了避免这些问题,通常需要在多线程环境下使用线程安全的数据结构,或者采用同步机制来保护共享数据的访问。下面是一个示例,演示了在多线程环境下操作 ArrayList 可能引发的线程不安全问题:
import java.util.ArrayList;
public class UnsafeArrayListExample {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
// 创建并启动多个线程同时向 ArrayList 中添加元素
for (int i = 0; i < 5; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
arrayList.add(j);
}
}).start();
}
// 等待所有线程执行完毕
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出 ArrayList 中的元素个数
System.out.println("Size of ArrayList: " + arrayList.size());
}
}
栈溢出通常是由于以下原因之一导致的:
下面是一些示例代码,演示了可能导致栈溢出的情况:
public class StackOverflowExample {
public static void main(String[] args) {
recursiveCall(0);
}
public static void recursiveCall(int n) {
recursiveCall(n + 1);
}
}
fifinally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
public class Main {
public static void main(String[] args) {
System.out.println(test());
}
public static int test() {
try {
System.out.println("In try block");
return 1;
} catch (Exception e) {
System.out.println("In catch block");
return 2;
} finally {
System.out.println("In finally block");
}
}
}
在 Java 中,无论在 try
块中是否有 return
语句,finally
块都会执行。finally
块通常用于释放资源或执行清理操作,无论 try
块中是否发生异常,都会执行 finally
块。
使用 BigDecimal
类可以避免浮点数精度问题,确保得到精确的计算结果。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal result = new BigDecimal("3").multiply(new BigDecimal("0.1"));
System.out.println(result); // 输出:0.3
}
}
在 Java 中,3 * 0.1
应该返回 0.3
,但由于浮点数的精度问题,可能会出现计算结果不准确的情况。这是因为在计算机中,浮点数的表示方式是有限的,而某些十进制小数无法精确地表示为二进制小数。
因此,当我们执行 3 * 0.1
这样的计算时,可能会出现一个非精确的结果。在实际测试中,可能会得到 0.30000000000000004
或者 0.29999999999999999
这样的结果,而不是精确的 0.3
。这是由于浮点数的精度问题导致的。
为了避免由于浮点数精度问题导致的误差,通常建议在需要精确计算的场景中,使用 BigDecimal
类进行计算。
使用序列化机制创建对象(需要实现 Serializable
接口):
import java.io.*;
public class SerializationExample {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 使用序列化机制创建对象
MyClass obj1 = new MyClass();
// 将对象写入到字节流中
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj1);
// 从字节流中读取对象
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
MyClass obj2 = (MyClass) objectInputStream.readObject();
obj2.printMessage(); // 输出:Hello, world!
}
}
使用 clone()
方法创建对象(需要实现 Cloneable
接口):
public class CloneExample {
public static void main(String[] args) throws CloneNotSupportedException {
// 使用 clone() 方法创建对象
MyClass obj1 = new MyClass();
MyClass obj2 = (MyClass) obj1.clone();
obj2.printMessage(); // 输出:Hello, world!
}
}
使用 new
关键字创建新对象:
public class NewObjectExample {
public static void main(String[] args) {
// 使用 new 关键字创建新对象
MyClass obj = new MyClass();
obj.printMessage(); // 输出:Hello, world!
}
}
class MyClass {
public void printMessage() {
System.out.println("Hello, world!");
}
}
使用反射机制创建对象:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectionExample {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 使用反射机制创建对象
Class<MyClass> cls = MyClass.class;
Constructor<MyClass> constructor = cls.getConstructor();
MyClass obj = constructor.newInstance();
obj.printMessage(); // 输出:Hello, world!
}
}
import java.util.concurrent.ConcurrentHashMap;
public class Main {
public static void main(String[] args) {
// 创建一个 ConcurrentHashMap
ConcurrentHashMap<Integer, String> concurrentHashMap = new ConcurrentHashMap<>();
// 创建并启动多个线程
for (int i = 0; i < 5; i++) {
int finalI = i;
new Thread(() -> {
// 向 ConcurrentHashMap 中添加元素
for (int j = 0; j < 10; j++) {
concurrentHashMap.put(finalI * 10 + j, "Value_" + finalI + "_" + j);
System.out.println(Thread.currentThread().getName() + " added: " + finalI * 10 + j);
}
}).start();
}
// 等待所有线程执行完毕
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出 ConcurrentHashMap 中的所有元素
System.out.println("ConcurrentHashMap: " + concurrentHashMap);
}
}
当需要在多线程环境中操作时,可以使用线程安全的 ConcurrentHashMap
。
Hashtable
是线程安全的,但在性能上可能不如 HashMap
,因为 Hashtable
中的方法使用了 synchronized
关键字进行同步,这会造成一定的性能开销。因此,在不需要线程安全保证的情况下,推荐使用 HashMap
,在需要线程安全保证的情况下,再考虑使用 Hashtable
或者 ConcurrentHashMap
。
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
// 创建一个 Hashtable
Hashtable<Integer, String> hashtable = new Hashtable<>();
// 创建并启动多个线程
for (int i = 0; i < 5; i++) {
int finalI = i;
new Thread(() -> {
// 向 Hashtable 中添加元素
for (int j = 0; j < 10; j++) {
hashtable.put(finalI * 10 + j, "Value_" + finalI + "_" + j);
System.out.println(Thread.currentThread().getName() + " added: " + finalI * 10 + j);
}
}).start();
}
// 等待所有线程执行完毕
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出 Hashtable 中的所有元素
System.out.println("Hashtable: " + hashtable);
}
}
Hashtable
是线程安全的,因为它的每个方法都使用了 synchronized
关键字进行同步,这使得它可以直接用于多线程环境中。
目录和文件
mkdir 名称 => mkdir /data
mkdir -p 名称 => mkdir -p /data/node
touch 文件1 文件2 => touch 1.txt 2.txt
cp 文件 目录 => cp 1.txt /opt/data
cp 文件 目录 => cp 1.txt /opt/data/2.txt
mv 目录 目录 => mv data /opt
mv 目录 目录 => mv data /opt/data2
rm -rf data
chmod 777 -R 目录 => chmod 777 -R data
tar -zxvf 压缩包 => tar -zxvf 1.tar.gz
unzip 压缩包 => unzip 1.zip
pwd
cat 目录 => cat 1.txt
vi 目录 => vi 1.txt
echo 内容 >> 文件 => echo '111' >> 1.txt
tail -n 行数 文件 => tail -n 1000 1.txt
find /-name 文件 => find /-name 1.txt #网络
service network restart #防火墙
systemctl stop firewalld.service
systemctl restart firewalld.service
systemctl start firewalld.service
systemctl status firewalld.service
systemctl enable firewalld.service
systemctl disable firewalld.service
firewalld-cmd --list-ports
firewalld-cmd --zone=public --add-port=端口/tcp --permanent => firewalld-cmd --zone=public --add-port=8080/tcp --permanent
firewalld-cmd --reload #服务
systemctl list-run-files
systemctl disable 服务 => systemctl disable mysql
systemctl enable 服务 => systemctl enable mysql #磁盘
df -h #进程
netstat -ntlp
ps -ef|grep 进程名 => ps -ef|grep java
netstat -tunlp|grep 端口 => netstat -tunlp|grep 8080
ps -aux
kill 进程 => kill 884
kill -9 进程 => kill -9 884 #CPU
top #账号
su 账号 => su root
useradd 用户名 => useradd mysql
useradd -g 组名 用户名 => useradd -g mysql-group mysql
passwd 用户名 => passwd mysql
userdel 用户名 => userdel mysql
whomi
Docker
uname -r
systemctl start docker
systemctl status docker
systemctl restart docker
docker version
docker info
docker --help
docker images
docker run -d -p 对外端口:容器端口 镜像名称 => docker run -d -p 6379:6379 redis
docker logs 容器id => docker logs xz2wxdf
docker search 镜像名称 => docker search jdk
docker tag 镜像名称:标签 => docker tag redis:7.0.1
docker rmi 镜像id => docker rmi dxfdxzsa
docker exec -it 容器id /bin/bash => docker exec -it xsdfds /bin/bash
docker restart 容器id => docker restart xsddf
docker ps --a
docker stop 容器id => docker stop exfds
docker rm 容器id => docker rm xsdfds
docker kill 容器id
docker inspect 容器id
docker volume ls
docker volume inspect 卷名 => docker volume inspect /data
dokcer build -t 镜像名称:标签 . => docker build -t jdk:21 . #docker-compose
docker-compose build
docker-compose build --no-cache
docker-compose images
docker-compose up -d
docker-compose ps -a
docker-compose exec 容器名 bash => docker-compose exec nginx bash
docker-compose stop
docker-compose down
docker-compose stop 容器名称 => docker-compose stop nginx
docker-compose up -d 容器名称 => docker-compose up -d nginx
docker-compose restart 容器名称 => docker-compose restart nginx
docker-compose rm
docker-compose logs -f 容器名称 => docker-compose logs -f nginx
docker-compose top
yaml配置
nacos使用https和http协议,只要注册临时服务,都是走RPC,因此使用https需要改为https
spring:
cloud:
# nacos
nacos:
discovery:
server-addr: https://127.0.0.1:8848
namespace: public
username: nacos
password: nacos
group: LAOKOU_GROUP
# https
secure: true
# true 临时 false 持久
ephemeral: true
config:
server-addr: https://127.0.0.1:8848
namespace: public
username: nacos
password: nacos
# 指定读取的文件格式
file-extension: yaml
group: LAOKOU_GROUP
refresh-enabled: true
keytool命令详解
1.生成pfx证书(.p12是pfx的新格式)
keytool -genkey
-alias laokou-register # 证书别名,不区分大小写
-storetype PKCS12 # 密钥库类型,常用类型有JKS、PKCS12
-keyalg RSA # 密钥算法,可选密钥算法:RSA\DSA,默认DSA
-keysize 2048 # 密钥长度(RSA=2048,DSA=2048)
-keystore scg-keystore.p12 # 密钥库文件名称
-validity 3650 # 证书有效天数
2.导出证书为cer(cer/crt是证书的公钥格式,cer是crt证书的微软形式)
keytool -exportcert -v
-alias laokou-register # 证书别名,不区分大小写
-keystore scg-keystore.p12 # 密钥库文件名称
-storepass laokou # 密钥库口令,推荐与keypass一致(获取keystore信息所需要密码)
-file register.cer # 导出的文件名
import java.util.Hashtable;
import java.util.Enumeration;
public class Main {
public static void main(String[] args) {
// 创建一个 Hashtable
Hashtable<Integer, String> hashtable = new Hashtable<>();
// 添加元素到 Hashtable
hashtable.put(1, "Apple");
hashtable.put(2, "Banana");
hashtable.put(3, "Orange");
// 获取 Hashtable 中的值的枚举
Enumeration<String> values = hashtable.elements();
// 遍历枚举并输出值
while (values.hasMoreElements()) {
System.out.println(values.nextElement());
}
}
}
Hashtable
类的 elements()
方法用于返回此 Hashtable
中的值的枚举(Enumeration)。
LinkedList 是 Java 中的双向链表实现。在 LinkedList 中,每个节点都包含对前一个节点和后一个节点的引用,这使得在链表中插入和删除元素的操作更加高效,因为它不需要像数组那样移动其他元素来保持顺序。
以下是 LinkedList 的基本特点:
import java.util.LinkedList;
public class LinkedListExample {
public static void main(String[] args) {
// 创建一个 LinkedList
LinkedList<String> linkedList = new LinkedList<>();
// 添加元素到 LinkedList
linkedList.add("Apple");
linkedList.add("Banana");
linkedList.add("Orange");
// 访问元素
System.out.println("LinkedList: " + linkedList);
// 获取第一个和最后一个元素
String firstFruit = linkedList.getFirst();
String lastFruit = linkedList.getLast();
System.out.println("First fruit: " + firstFruit);
System.out.println("Last fruit: " + lastFruit);
// 添加元素到列表的开头和末尾
linkedList.addFirst("Grape");
linkedList.addLast("Watermelon");
System.out.println("LinkedList after adding first and last elements: " + linkedList);
// 删除第一个和最后一个元素
linkedList.removeFirst();
linkedList.removeLast();
System.out.println("LinkedList after removing first and last elements: " + linkedList);
// 获取元素个数
int size = linkedList.size();
System.out.println("Size of LinkedList: " + size);
// 判断是否包含某个元素
boolean containsBanana = linkedList.contains("Banana");
System.out.println("LinkedList contains 'Banana': " + containsBanana);
}
}
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
// 创建一个 ArrayList
ArrayList<String> arrayList = new ArrayList<>();
// 添加元素到 ArrayList
arrayList.add("Apple");
arrayList.add("Banana");
arrayList.add("Orange");
// 访问元素
System.out.println("ArrayList: " + arrayList);
// 获取指定位置的元素
String fruit = arrayList.get(1);
System.out.println("Fruit at index 1: " + fruit);
// 修改元素
arrayList.set(0, "Grape");
System.out.println("Updated ArrayList: " + arrayList);
// 删除元素
arrayList.remove(2);
System.out.println("ArrayList after removing element at index 2: " + arrayList);
// 获取元素个数
int size = arrayList.size();
System.out.println("Size of ArrayList: " + size);
// 判断是否包含某个元素
boolean containsBanana = arrayList.contains("Banana");
System.out.println("ArrayList contains 'Banana': " + containsBanana);
}
}
ArrayList 适用于随机访问和遍历操作,而 LinkedList 适用于频繁的插入和删除操作
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
// 创建一个数组
String[] array = {"apple", "banana", "orange"};
// 使用 asList 方法将数组转换为列表
List<String> list = Arrays.asList(array);
// 修改原数组或列表中的元素
array[0] = "grape";
list.set(1, "watermelon");
// 打印数组和列表
System.out.println("Array: " + Arrays.toString(array));
System.out.println("List: " + list);
}
}