JUC基础(周阳老师笔记

article/2025/10/12 7:04:23

目录

  • 一、JMM
    • 1.volatile
    • 2.加载代码练习:
  • 二、JUC基础
    • 1.什么是进程/线程,并发/并行
      • 进程/线程
      • 并发/并行
    • 2.线程的状态
    • 3.线程 操作 资源类
    • 4.Lambda表达式
      • jdk8以后的interface
    • 5.判断/干活/通知
    • 6.防止虚假唤醒(while not if)
    • 7.标志位
      • lock精准通知
      • condition
    • 8.多线程八锁
  • 三、JUC集合类
    • 1.List
    • 2.set
  • 四、Callable接口
  • 五、强大的辅助类
    • 1.countDownLatch
    • 2.CyclicBarrier
    • 3.Semaphore
  • 六、ReentrantReadWriteLock
  • 七、阻塞队列
  • 八、线程池
    • 1.线程池的优点
    • 2.线程池的创建
      • Executors工具类的三种预设方案(实际开发中一般不用)
    • 3.七大参数
    • 4.线程池的底层工作原理
      • 阿里巴巴开发手册不让用三个预设(Executors),自定义自己写,这样也清晰(七大参数)
    • 5.自定义线程池:`ThreadPoolExecutor`核心类
    • 6.确定线程池的大小
  • 九、Java8新特性
    • 1.四大函数式接口
    • 2.Stream流式计算
  • 十、其他类
    • 1.分支合并框架
      • 相关类
      • 具体使用代码
    • 2.异步回调

一、JMM

1.volatile

volatile是java虚拟机提供的轻量级的同步机制(青春版synchronized)

可以保证可见性、有序性(指令重排序),但不能保证原子性

主内存是线程共享的。

JVM会从主内存中拷贝变量到线程中,即工作变量,工作变量是线程私有的。

volatile关键字的变量会在工作变量改变后,通知其他线程丢弃其拷贝重新在主内存中拷贝一份到自己的工作空间。

2.加载代码练习:

加载顺序:静态代码块>普通代码块>构造方法

静态代码直接放进方法区,第二次就不再需要加载了,直接指向方法区


二、JUC基础

  • 口诀:
  1. 高内聚低耦合前提下,线程操作资源类
  2. 判断/干活/通知
  3. 多线程交互中要防止多线程的虚假唤醒(判断只用while,不用if)
  4. 标志位

1.什么是进程/线程,并发/并行

进程/线程

进程就是idea,线程就是idea中的

详细一点进程就是操作系统分配资源的基本单位,线程比进程笑,是独立运行和调度的基本单位

并发/并行

并发就是同一时刻操作同一资源

并行就是同一时间操作同一资源(CPU在极短的时间段内完成时间片轮转)

2.线程的状态

public enum State {
NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
}

new Thread().start()之后不是立马运行,只是就绪状态,要等待操作系统的cpu调度

3.线程 操作 资源类

操作就是对外暴露的调用方法。

  1. 创建资源类,不要去继承Thread类或者实现Runnable接口,就让他是一个纯净的资源类
  2. 用synchronized标识共享资源(旧) /

用ReentrantLock(可重入锁)来锁局部代码块(新),从而缩小我锁的粒度范围,不要一竿子打死,这样我的并发性就好、高

资源类中要:private Lock lock = new ReentrantLock();

ReentrantLock像公厕坑位的锁,synchronized就是公厕大门的锁

(学会用idea的live template来抽取代码为自定义快捷输入)(语法糖)

4.Lambda表达式

  • 口诀:拷贝小括号,写死右箭头,落地大括号

匿名内部类代码太长,所以要用lambda表达式简化代码

如果要用lambda表达式,接口必须是函数式接口(functional interface)

可以直接在接口上加@FuctionalInterface注解帮助校验,不加的话java也会自己帮我们加

jdk8以后的interface

可以有部分带实现的方法 default

可以有静态方法(接口名直接调用)

5.判断/干活/通知

这里判断直接上while是为了方便能够运行,教程中先是if为了引出虚假唤醒的问题。

老版写法(synchronized):

class Bakery{private int cake = 0;public synchronized void increment() throws InterruptedException {while(cake!=0){this.wait();}cake++;System.out.println(Thread.currentThread().getName()+"\t 数量:"+cake);this.notifyAll();}public synchronized void decrement() throws InterruptedException {while(cake==0){this.wait();}cake--;System.out.println(Thread.currentThread().getName()+"\t 数量:"+cake);this.notifyAll();}}public class ProducerAndConsumer {public static void main(String[] args) {Bakery bakery = new Bakery();new Thread(()->{try {for(int i =1;i<=10;i++) bakery.increment();} catch (InterruptedException e) {e.printStackTrace();}},"蛋糕师1").start();new Thread(()->{try {for(int i =1;i<=10;i++) bakery.increment();} catch (InterruptedException e) {e.printStackTrace();}},"蛋糕师2").start();new Thread(()->{try {for(int i =1;i<=10;i++) bakery.decrement();} catch (InterruptedException e) {e.printStackTrace();}},"消费者1").start();new Thread(()->{try {for(int i =1;i<=10;i++) bakery.decrement();} catch (InterruptedException e) {e.printStackTrace();}},"消费者2").start();}
}

新版本(ReentrantLock版本): (main方法就不写了)

lock配合condition的await和signal 对应synchronized配合object的wait和notify

class Bakery {private int cake = 0;private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();public void increment() throws InterruptedException {lock.lock();try {while (cake != 0) {condition.await();}cake++;System.out.println(Thread.currentThread().getName() + "\t 数量:" + cake);condition.signalAll();} finally {lock.unlock();}}public void decrement() throws InterruptedException {lock.lock();try {while (cake == 0) {condition.await();}cake--;System.out.println(Thread.currentThread().getName() + "\t 数量:" + cake);condition.signalAll();} finally {lock.unlock();}}}

6.防止虚假唤醒(while not if)

虚假唤醒的原因:

可能因为多个进程进入if后被wait,而if只判断一次,然后因为某个线程的notifyAll后再执行下去,导致连续多次++或—

解决:把原来的if换成while,让他们即使被唤醒了,仍要重新判断

7.标志位

使用标志位可以实现精准通知(我做完了你做,实现多线程之间的顺序调用)

lock精准通知

lock配合condition的await和signal 对应synchronized配合object的wait和notify

class SharedResource {private int sharedreference = 1;private Lock lock = new ReentrantLock();//condition1 != condition2 != condition3private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();private int num = 1;public void share01() throws InterruptedException {lock.lock();try {while (num != 1) {condition1.await();}System.out.println(Thread.currentThread().getName() + "\t进入");num = 2;condition2.signal();} finally {lock.unlock();}}public void share02() throws InterruptedException {lock.lock();try {while (num != 2) {condition2.await();}System.out.println(Thread.currentThread().getName() + "\t进入");num = 3;condition3.signal();} finally {lock.unlock();}}public void share03() throws InterruptedException {lock.lock();try {while (num != 3) {condition3.await();}System.out.println(Thread.currentThread().getName() + "\t进入");num = 1;condition1.signal();} finally {lock.unlock();}}}public class SequenceSignal {public static void main(String[] args) {SharedResource sharedResource = new SharedResource();new Thread(() -> {try {for (int i = 1; i <= 10; i++) sharedResource.share01();} catch (InterruptedException e) {e.printStackTrace();}}, "Thread 1").start();new Thread(() -> {try {for (int i = 1; i <= 10; i++) sharedResource.share02();} catch (InterruptedException e) {e.printStackTrace();}}, "Thread 2").start();new Thread(() -> {try {for (int i = 1; i <= 10; i++) sharedResource.share03();} catch (InterruptedException e) {e.printStackTrace();}}, "Thread 3").start();}
}

condition

为了搞清楚精准通知的原理,应该先要弄懂condition是到底是个什么东西

一个Condition实例本质上绑定到一个锁

一定要看下面这个链接,这会马上备考概率论了所以没看

https://segmentfault.com/a/1190000037693391

8.多线程八锁

class Phone {public synchronized void sendEmail() throws InterruptedException {TimeUnit.SECONDS.sleep(2);System.out.println("============sendEmail");}public  synchronized void sendSMS() {System.out.println("============sendSMS");}public void hello(){System.out.println("======HelloWorld");}
}public class EightLock {public static void main(String[] args) {Phone phone = new Phone();new Thread(() -> {try {phone.sendEmail();} catch (Exception e) {e.printStackTrace();}}, "A").start();new Thread(() -> {try {phone.sendSMS();} catch (Exception e) {e.printStackTrace();}}, "B").start();}
}
邮件在先,短信在后1 标准访问,先打印短信还是邮件-----------------------------------邮件
2 停4秒在邮件方法内,先打印短信还是邮件---------------------------邮件
3 普通的hello方法,是先打邮件还是hello--------------------------hello
4 现在有两部手机,先打印短信还是邮件-----------------------------短信
5 两个静态同步方法,1部手机,先打印短信还是邮件-------------------邮件
6 两个静态同步方法,2部手机,先打印短信还是邮件-------------------邮件
7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件----短信
8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件----短信

main线程里写的线程代码先后执行顺序还真不一定 ,需要等待操作系统对线程优先级排序 阻塞的数字啥的

TimeUnit.SECONDS.sleep()

原因:(前提得锁的对象是一致才能发挥锁的作用)

1、2:synchronized锁的是当前对象this,即phone1

3:锁的东西不一样,普通方法不会去抢,各不相干

4:锁的不一样对象(2部手机),因为邮件要挂2s,所以先短信

5、6:synchronized修饰静态方法锁的是整个类,即class,而不是对象

7、8:锁的不是一个东西


三、JUC集合类

1.List

请举例说明List不安全:(add没有synchronized修饰)

报:java.util.ConcurrentModificationException

  • ArrayList、StringBuilder、CopyOnWriteArrayList底层都用到了Arrays.copyOf
  • Arrays.copyOf方法返回原始数组的副本,截断或填充空值以获得指定的长度。

ArrayList:

在这里插入图片描述

CopyOnWriteArrayList:

CopyOnWrite即写时复制的容器。往容器中添加元素的时候,不直接往当前容器添加,而是先复制出一个新的容器,往新的容器中添加元素。添加完成后再将原容器的引用指向新容器setArray(newElements);。这样就能并发的读而不需要加锁,这是一种读写分离的思想,读和写不同的容器。

在这里插入图片描述

StringBuilder:
在这里插入图片描述

解决:

ArrayList<Object> objects = new ArrayList<>();//线程不安全
Vector<Object> objects2 = new Vector<>(); //线程安全,全是synchronized修饰,基本不用,性能太差
Collections.synchronizedList(objects);//转化为线程安全
CopyOnWriteArrayList<Object> objects1 = new CopyOnWriteArrayList<>();//线程安全,写时复制

2.set

hashset的底层是hashmap

hashset的add调的是hashmap的put value是PRESENT的常量

concurrenthashmap copyonwriteset 线程安全(没有深入,最好深入一下)

https://segmentfault.com/a/1190000021144667 性能对比

又带着复习了一遍hashmap,数组+链表+红黑树

负载因子*当前容量=threshold 门槛


四、Callable接口

  • 与继承thread类、实现runnable接口相比,实现callable接口有返回值、有异常,重写方法不一样。

因为Thread的构造方法中只提供了runnable接口,没有callable接口

所以根据多态的性质,我们需要一个同时实现了runnable和callable接口的类,即futuretask类

FutureTask,实现了runnable接口,构造方法可以传入callable接口

在这里插入图片描述

在这里插入图片描述

然后在thread中传入futuretask,具体代码如下

class Mythread implements Callable<Integer>{@Overridepublic Integer call() throws Exception {System.out.println("******进入future方法");TimeUnit.SECONDS.sleep(2);return 123;}
}
public class MyCallable {public static void main(String[] args) throws ExecutionException, InterruptedException {Mythread mythread = new Mythread();FutureTask<Integer> integerFutureTask = new FutureTask<>(mythread);for(int i=1;i<=10;i++){new Thread(integerFutureTask,String.valueOf(i)).start();}System.out.println("计算完成");System.out.println(integerFutureTask.get());//get不到会阻塞主线程,所以get一般放在最后}
}

注意细节:

get不到会阻塞主线程,所以get一般放在最后

一个futuretask 多个线程调用只会调用一次,内部有缓存。

futuretask.get 帮忙计算买水的例子


五、强大的辅助类

1.countDownLatch

上晚自习班长关门的例子

countDownLatch : 计数器

CountDownLatch countDownLatch = new CountDownLatch(5);
for(int i=1;i<=5;i++)
new Thread(()->{System.out.println(Thread.currentThread().getName()+"走出了教室");countDownLatch.countDown();},String.valueOf(i)).start();countDownLatch.await();
System.out.println("========班长关门了");

CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。

其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),

当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行。

2.CyclicBarrier

CyclicBarrier : 到齐开会,集齐龙珠

CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {System.out.println("开始开会");});
for (int i = 1; i <= 5; i++) {new Thread(() -> {try {System.out.println(Thread.currentThread().getName() + "进入了会议室");cyclicBarrier.await();} catch (Exception e) {e.printStackTrace();}}, String.valueOf(i)).start();
}=

CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

线程进入屏障通过CyclicBarrier的await()方法

3.Semaphore

信号量机制:争车位。

信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。

Semaphore semaphore = new Semaphore(2);
for (int i = 1; i <= 5; i++) {new Thread(() -> {try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + "进入了停车场");TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + "离开了停车场");semaphore.release();}}, String.valueOf(i)).start();
}

也能利用信号量机制实现synchronized实现不到的效果,如让一个线程每次拿到10s锁就释放


六、ReentrantReadWriteLock

读写锁。

class MyCache {private volatile Map<String, Object> map = new HashMap<>();private ReentrantReadWriteLock readwriteLock=new ReentrantReadWriteLock();public void put(String key, Object value) {readwriteLock.writeLock().lock();System.out.println(Thread.currentThread().getName() + "\t 正在写" + key);//暂停一会儿线程try {//TimeUnit.SECONDS.sleep(2);} catch (Exception e) {e.printStackTrace();}map.put(key, value);System.out.println(Thread.currentThread().getName() + "\t 写完了" + key);readwriteLock.writeLock().unlock();}public Object get(String key) {readwriteLock.readLock().lock();Object result = null;System.out.println(Thread.currentThread().getName() + "\t 正在读" + key);try {TimeUnit.SECONDS.sleep(2);result = map.get(key);System.out.println(Thread.currentThread().getName() + "\t 读完了" + result);} catch (Exception e) {e.printStackTrace();}finally {readwriteLock.readLock().unlock();}return result;//return 前会执行finally}
}public class ReadwriteLock {public static void main(String[] args) {MyCache myCache = new MyCache();for (int i = 1; i <= 5; i++) {final int num = i;new Thread(() -> {myCache.get(String.valueOf(num));}, String.valueOf(i)).start();}for (int i = 1; i <= 5; i++) {final int num = i;new Thread(() -> {myCache.put(String.valueOf(num), String.valueOf(num));}, String.valueOf(i)).start();}}
}

七、阻塞队列

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

add throwing an IllegalStateException if this queue is full

offer returning true upon success and false if this queue is full. This method is generally preferable to method add(E)

put 阻塞无返回值

offer(e,time,unit) 带返回值,阻塞超时退出 (这个好诶)


八、线程池

银行窗口,办理业务,请xx到x号窗口办理业务

1.线程池的优点

就像数据库连接池一样,我们频繁创建销毁线程需要消耗资源,于是用线程池来控制运行的线程数量。

处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果任务数量超过了最大线程数量,超出数量的任务排队等候(阻塞队列),等其他线程执行完毕,再从队列中取出任务来执行。

它的主要特点为:线程复用;控制最大并发数;管理线程。

2.线程池的创建

主要是通过Executor框架实现的,核心是ThreadPoolExecutor类,我们自定义也是用这个类
在这里插入图片描述

Executors工具类的三种预设方案(实际开发中一般不用)

在这里插入图片描述

3.七大参数

在这里插入图片描述

在这里插入图片描述

corePoolSize:核心线程数

maximumPoolSize:池子的最大线程数

keepAliveTime:非核心线程数空闲持续时间

unit:时间单位

workQueue:阻塞队列

threadFactory:线程创建的工厂,一般为默认

handler:拒绝策略

4.线程池的底层工作原理

先核心线程工作,如果繁忙,任务进阻塞队列

如果阻塞队列满了,就会扩容到池子最大线程数

如果还是让阻塞队列满了,就会进行拒绝策略

然后当一个线程无事可做超过keepAliveTime时间,那么如果当前线程数量大于corePoolSize,这个线程就会被停掉。所以线程池的所有任务完成后,最终收缩到corePoolSize的大小

阿里巴巴开发手册不让用三个预设(Executors),自定义自己写,这样也清晰(七大参数)

在这里插入图片描述

5.自定义线程池:ThreadPoolExecutor核心类

threadPool.execute(()→{}); 线程池执行

threadPool.shutdown(); 线程池关闭

在这里插入图片描述

public static void main(String[] args) {ExecutorService myThreadPool = new ThreadPoolExecutor(2,  //corePoolSie5, //maximumPoolSize2L,  //keepAliveTimeTimeUnit.SECONDS, //unitnew ArrayBlockingQueue<>(3), //workQueueExecutors.defaultThreadFactory(), //threadFactorynew ThreadPoolExecutor.AbortPolicy()   //handler 【默认】//new ThreadPoolExecutor.CallerRunsPolicy() //handler//new ThreadPoolExecutor.CallerRunsPolicy() //handler//new ThreadPoolExecutor.DiscardPolicy() //handler);try {//10个顾客请求for (int i = 1; i <= 10; i++) { //最大容纳数是:maximumPoolSize+workQueue 5+3=8myThreadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "\t 办理业务");});}} catch (Exception e) {e.printStackTrace();} finally {myThreadPool.shutdown();}
}

6.确定线程池的大小

不写死,Runtime.getRuntime().availableProcessors(); 获得cpu核数

根据具体业务设定最大线程数:

  • CPU密集型:大量计算,cpu 占用越接近 100%;Nthreads = Ncpu+1
  • IO密集型:大量网络,文件操作;Nthreads = Ncpu x Ucpu x (1 + W/C),

详见《Java并发编程实践》

  • Ncpu = CPU的数量
  • Ucpu = 目标CPU的使用率, 0 <= Ucpu <= 1
  • W/C = 等待时间与计算时间的比率

九、Java8新特性

1.四大函数式接口

使用 @FunctionalInterface 标识,有且仅有一个抽象方法,可被隐式转换为 lambda 表达式

在这里插入图片描述

如果代码量只有一行,可以适当简化lambda表达式

在这里插入图片描述

2.Stream流式计算

  • 集合讲的是数据,流讲的是计算
  • 注意:Stream流式计算 和 IO文件读写流 两者完全不是一回事

特点:

  • Stream自己不会存储数据,不会改变源对象,他们会返回一个持有结果的新Stream
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream 类:引入函数式编程风格,提供了很多功能,使代码更加简洁。方法包括 forEach 遍历、count 统计个数、filter 按条件过滤、limit 取前 n 个元素、skip 跳过前 n 个元素、map 映射加工、concat 合并 stream 流等。

这一些列方法需要传入四大函数式接口,传入的参数是stream流。

如:

User u1 = new User(1,"a",10);
User u2 = new User(2,"b",17);
User u3 = new User(3,"c",20);
User u4 = new User(4,"d",28);
User u5 = new User(5,"e",30);
List<User> users = Arrays.asList(u1, u2, u3, u4, u5);
users.stream().filter(p -> {return p.getId() % 2 == 0;
}).filter(p -> {return p.getAge() > 24;
}).map(f -> {return f.getUserName().toUpperCase();
}).sorted((o1, o2) -> {return o2.compareTo(o1);
}).limit(1).forEach(System.out::println);

十、其他类

1.分支合并框架

Fork:把一个复杂任务进行分拆,大事化小
Join:把分拆任务的结果进行合并

主要还是分治的思想,只不过这里是多个线程分治

相关类

  • ForkJoinPool:分支合并池(类似线程池)
  • ForkJoinTask:(类似FutureTask的构造方法接callable),这里要用Pool的submit方法
  • RecursiveTask:抽象类继承自ForkJoinTask,用来被继承,重写compute方法;这里作多线程的递归

在这里插入图片描述

具体使用代码

class MyTask extends RecursiveTask<Integer> {private static final Integer ADJUST_VALUE = 10;private int begin;private int end;private int result;public MyTask(int begin, int end) {this.begin = begin;this.end = end;}@Overrideprotected Integer compute() {if ((end - begin) <= ADJUST_VALUE) { //10以内太小了就没必要拆分了for (int i = begin; i <= end; i++) {result = result + i;}} else {int middle = (begin + end) / 2;MyTask task01 = new MyTask(begin, middle);MyTask task02 = new MyTask(middle + 1, end);task01.fork();task02.fork();result = task01.join() + task02.join();}return result;}
}public class ForkJoinDemo {public static void main(String[] args) throws Exception {MyTask myTask = new MyTask(0, 100); //继承了RecursiveTask,实现0~100的相加ForkJoinPool forkJoinPool = new ForkJoinPool();ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask); //分支合并池提交TaskSystem.out.println(forkJoinTask.get());forkJoinPool.shutdown();}
}

2.异步回调

public static void main(String[] args) throws Exception {CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(()->{ //Void是void包装类System.out.println(Thread.currentThread().getName()+"没有返回值,update mysql ok");});completableFuture1.get();//------------------------------------------------------------------------------------------CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getName()+"有返回值,insert mysql ok");int i = 1/0;return 1024;});System.out.println(completableFuture2.whenComplete((t, u) -> {  // BiConsumer<? super T, ? super Throwable> action 要有两个输入参数,且没有返回值System.out.println("t=" + t); //t:正确完成System.out.println("u=" + u); //u:异常}).exceptionally(f -> {   //如果异常,则走这里System.out.println("exception:" + f.getMessage());return 404;}).get());}

http://chatgpt.dhexx.cn/article/Fy5eoYC8.shtml

相关文章

什么是JUC

什么是JUC JUC指的是&#xff1a;Java里的三个包 java.util.concurrentjava.util.concurrent.atomic&#xff1a;原子性java.util.concurrent.locks&#xff1a;lock锁 回顾线程和进程 进程 程序执行的一次过程&#xff0c;一个进程包含一个或多个线程。进程是资源分配的单位…

Java - JUC详解

目录 一、了解和JUC相关的概念 二、Java线程 三、线程共享模型 一、了解和JUC相关的概念 1.1 什么是JUC&#xff1f; JUC是java.util.concurrent包的简称&#xff0c;在Java5.0添加&#xff0c;目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和…

JUC线程池

一、JUC介绍 java.util.concurrent包&#xff08;简称&#xff1a;JUC&#xff09;。JUC主要是让开发者在多线程编程中更加简单、方便一些。 通过JDK内置了一些类、接口、关键字&#xff0c;补充完善了JDK对于并发编程支持的“短板”。 主要功能&#xff1a;&#xff08;1&am…

JUC

&#xff08;尚硅谷笔记&#xff09; Java JUC 简介  在 Java 5.0 提供了 java.util.concurrent &#xff08;简称 JUC &#xff09;包&#xff0c;在此包中增加了在并发编程中很常用 的实用工具类&#xff0c;用于定义类似于线程的自定义子 系统&#xff0c;包括线程池、异…

JUC基础知识(个人总结)

声明: 1. 本文为我的个人复习总结, 并非那种从零基础开始普及知识 内容详细全面, 言辞官方的文章 2. 由于是个人总结, 所以用最精简的话语来写文章 3. 若有错误不当之处, 请指出 一. 前置基础: IO 操作不占用 cpu, 只是我们一般拷贝文件使用的是【…

1、JUC概述

1.1 什么是JUC 在Java中&#xff0c;线程部分是一个重点&#xff0c;本篇文章说的JUC 也是关于线程的。JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包&#xff0c;JDK1.5开始出现的。 1.2 线程和进程的概念 进程和线程 进程&#xff08;Process&…

JUC基础【万字篇】

JUC 1、什么是JUC JUC&#xff1a;指的是java.util三个并发编程工具包 java.util.concurrentjava.util.concurrent.atomicjava.util.concurrent.locks 实现多线程的四种方式&#xff1a; 继承Thread类实现Runnable接口实现Callable接口线程池 业务&#xff1a;普通的线程代…

java--JUC快速入门(彻底搞懂JUC)

java–JUC快速入门&#xff08;彻底搞懂JUC&#xff09; 文章目录 java--JUC快速入门&#xff08;彻底搞懂JUC&#xff09;1、学习多线程之前需要知道的一些概念。2、JUC的结构3、Lock锁(重点)4、集合类不安全5、Callable()6、常用的辅助类7、读写锁8、阻塞队列9、线程池 1、学…

Dbeaver做数据迁移

1、选择源头数据库的表、鼠标右击、选择导出数据 2、在数据转化弹框中&#xff0c;双击 ‘数据库&#xff0c;数据表’ 那一栏 3、选择目标数据库&#xff0c;调整字段类型映射关系 4、调整字段的映射关系 目前遇到的字段类型&#xff0c;只有 int&#xff0c;bigint 转 num…

dbeaver工具连接达梦数据库

、一 概述 DBeaver 是一个基于 Java 开发&#xff0c;免费开源的通用数据库管理和开发&#xff0c;DBeaver 采用 Eclipse 框架开发&#xff0c;支持插件扩展&#xff0c;并且提供了许多数据库管理工具&#xff1a;ER 图、数据导入/导出、数据库比较、模拟数据生成等&#xff0…

DBeaver 格式化sql

有时候我们拿到了一条sql语句是长长的&#xff0c;非常不容易阅读&#xff0c;这时我们就想说哪里可以格式下sql代码。 方法有很多种&#xff0c;这里我就用Dbeaver来格式化sql。 ①打开Dbeaver ②复制sql代码到SQL编辑器中&#xff0c;并选中 ③按ctrlshiftF&#xff0c;即…

【DBeaver】常用自定义设置

文章目录 背景一、用户界面设置1.1、22.3.4版本1.1.1、SQL编辑器-字体设置1.1.2、查询结果-字体设置 1.2、23.0.0版本1.2.1、应用字体&#xff08;导航栏等&#xff09;1.2.2、文本字体&#xff08;SQL输出、文本编辑器等&#xff09; 二、常规设置2.1、连接类型设置/环境设置 …

DBeaver导入Excel数据

目录 前言 导入准备 ​导入步骤 1.选中数据库表&#xff0c;右键&#xff0c;然后点击导入数据 2.双击CSV,选择待导入的文件 3.修改编码格式&#xff08;可选&#xff0c;不乱码不用&#xff09; 4.点击下一步&#xff0c;修改列的类型 5.一直下一步&#xff0c;点击…

Dbeaver基本使用

1&#xff1a;与plsql相比&#xff0c;Dbeaver没有右击直接查看表注释的功能&#xff0c;但是Dbeaver提供了一个“打开声明”的功能&#xff0c;里面可以查看一些比较实用的内容&#xff1a;表列注释、创建该表的create语句&#xff1a; 2&#xff1a;在一般开发的情况下&#…

【大数据】Hive可视化工具dbeaver

Hive可视化工具dbeaver 1、dbeaver基本介绍 dbeaver是一个图形化的界面工具&#xff0c;专门用于与各种数据库的集成&#xff0c;通过dbeaver我们可以与各种数据库进行集成通过图形化界面的方式来操作我们的数据库与数据库表&#xff0c;类似于我们的sqlyog或者navicat。 2、…

DBeaver安装及使用手册

一、DBeaver安装 1、在[DBeaver官网](https://dbeaver.io/download)进行数据库工具下载&#xff0c;下载好后双击运行2、选择语言后&#xff0c;点击OK 3、点击下一步 4、接受许可 5、选择可使用者&#xff0c;然后点击下一步 6、选择组件&#xff0c;一般选择默认即可 7…

DBeaver-Driver-All ( DBeaver驱动包,所有JDBC驱动整合包)

DBeaver-Driver-All DBeaver-Driver-All ( DBeaver驱动包 )整合所有DBeaver的JDBC驱动包&#xff0c;供DBeaver使用&#xff0c;无需每次都搜索和下载&#xff0c;只需clone本项目即可&#xff0c;一个包包含几乎所有的驱动&#xff0c;如果有缺漏的驱动欢迎提Issue补充。 DBe…

DBeaver 下载安装

1 下载地址(我下载的 Windows版本&#xff0c;根据系统需要选择版本) Releases dbeaver/dbeaver GitHubFree universal database tool and SQL client. Contribute to dbeaver/dbeaver development by creating an account on GitHub.https://github.com/dbeaver/dbeaver/rel…

DBeaver 安装

DBeaver 目录 DBeaver1、介绍2、发展史3、版本介绍4、下载与安装5、DBeaver 连接数据库&#xff08;MySql&#xff09;6、DBeaver 连接数据库&#xff08;Hive&#xff09;7、DBeaver 功能简介 1、介绍 DBeaver是一种通用数据库管理工具&#xff0c;适用于需要以专业方式使用数…

DBeaver驱动安装

最近打算用DBeaver它来查看SQLite文件&#xff0c;需要安装驱动&#xff0c;总是安装不上有点苦恼 下载驱动的时候可能会出现如下提示&#xff1a; Can’t create driver instance Error creating driver ‘SQLite’ instance. Most likely required jar files are missing. …