
Java
文章平均质量分 68
Java学习之路
学而不思则忘
一切都可以
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
Comparator比较器返回值理解
最近使用到了Comparator接口的compare方法,思考了一下改方法的返回值跟升序降序的关系。背景升序代码public void sortTest() { Integer[] nums = new Integer[]{1, 4, 3, 5, 2, 7, 6}; Arrays.sort(nums, new Comparator<Integer>() { @Override public int compare(Integer o1, .原创 2022-03-08 11:18:22 · 4892 阅读 · 1 评论 -
Java反射理解
1. 反射调用静态方法下面实例使用反射调用静态方法的两种类型:public和private创建一个类GreetingAndByepublic class GreetingAndBye { public static String greeting(String name) { return String.format("Hey %s, nice to meet you!", name); } private static String goodBye(S原创 2022-01-09 22:47:43 · 191 阅读 · 0 评论 -
AQS源码理解——ReentrantLock
公平锁策略ReentrantLock类中 FairSync 类源码解读:static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; // 公平锁入口 // 不响应中断的加锁 final void lock() { acquire(1); // (1) } /**原创 2021-12-12 17:50:10 · 315 阅读 · 0 评论 -
Java并发List
一. 并发场景下的List1. CopyOnWriteArrayListCopyOnWriteArrayList 是线程安全的 ArrayList。CopyOnWrite 意思为写的时候会将共享变量新复制一份出来。复制的好处在于读操作是无锁的(也就是无阻塞)。CopyOnWriteArrayList 仅适用于写操作非常少的场景,而且能够容忍读写的短暂不一致。如果读写比例均衡或者有大量写操作的话,使用 CopyOnWriteArrayList 的性能会非常糟糕。CopyOnWriteArrayList原创 2021-10-22 15:53:05 · 2298 阅读 · 0 评论 -
ArrayList线程不安全的原因
以下面代码为测试用例:public class ArrayListTest { private static final Logger LOGGER = LoggerFactory.getLogger(ArrayListTest.class); private static final ExecutorService threadPoolService = new ThreadPoolExecutor(100, 200, 5, TimeUnit.SECONDS,原创 2021-10-22 15:37:45 · 271 阅读 · 0 评论 -
单例模式的几种写法
1. 饿汉式(线程安全)容易产生垃圾对象。public class Singleton1 { private static final Singleton1 instance = new Singleton1(); private Singleton1() {} public static Singleton1 getInstance() { return instance; }}**2. 懒汉式(线程不安全) **public原创 2021-08-15 22:46:18 · 96 阅读 · 0 评论 -
基于AQS实现自定义同步器
下面是基于AQS实现的不可重入的独占锁:state为1表示锁已经被某一个线程持有,由于是不可重入锁,所以不需要记录持有锁的线程获取锁的次数。public class NonReentrantLock implements Lock, java.io.Serializable { private static class Sync extends AbstractQueuedSynchronizer { // 锁是否被持有 protected boolean is原创 2021-08-15 17:16:47 · 241 阅读 · 0 评论 -
抽象同步队列AQS概述
1. 抽象同步队列AQS概述AbstractQueuedSynchronizer(简称 AQS)是队列同步器,顾名思义,其主要作用是处理同步。它是并发锁和很多同步工具类的实现基石(如 ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore、FutureTask 等)。1. AQS的数据结构AQS 继承自 AbstractOwnableSynchronize,是一个FIFO的双向队列。public abstract class A原创 2021-08-15 15:41:55 · 228 阅读 · 0 评论 -
synchronized不捕获异常会导致锁释放
运行下面代码,如果不对异常处进行捕获,则结果如下:// 线程t1会中断,线程t2会进入代码继续执行t1 start.t1 count = 1t1 count = 2t1 count = 3t1 count = 4t1 count = 5Exception in thread "t1" java.lang.ArithmeticException: / by zero at thread.Catch.m(Catch.java:30) at thread.Catch.lambda$main$0原创 2021-08-12 19:48:30 · 498 阅读 · 0 评论 -
剑指 Offer 20. 表示数值的字符串
题目链接实现一个函数用来判断字符串是否表示数值(包括整数和小数)。数值(按顺序)可以分成以下几个部分:若干空格一个 小数 或者 整数(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个 整数若干空格小数(按顺序)可以分成以下几个部分:(可选)一个符号字符(’+’ 或 ‘-’)下述格式之一:至少一位数字,后面跟着一个点 ‘.’至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字一个点 ‘.’ ,后面跟着至少一位数字整数(按顺序)可以分成以下几个部分:(可选)一个原创 2021-06-18 19:39:52 · 83 阅读 · 0 评论 -
Integer.valueOf原理
看下面代码及输出:public class Five { public static void main(String[] args) { Integer a = Integer.valueOf(3); Integer b = Integer.valueOf(3); System.out.println(a == b); // true Integer c = Integer.valueOf(300000);原创 2021-06-18 18:57:24 · 1197 阅读 · 0 评论 -
static代码块作用
关于静态代码块:随着类的加载而执行,只执行一次,并且优于主函数。静态代码块是给类初始化的,构造代码块是给对象初始化的。静态代码块中的变量是局部变量,与普通函数中的局部变量性质没有区别。在类的加载过程中,static修饰的遍历会被初始化为0,然后再进行赋值。public class Four { private static int num = 1; static { num = 10; number = 50; System.o原创 2021-06-17 19:56:24 · 890 阅读 · 0 评论 -
Java的封装、继承、多态以及重载和重写
1. 面向对象编程三大特性1.1 封装隐藏对象的属性和实现细节,仅对外公开访问方法,控制在程序中属性的读和写的访问级别。封装基本要求把所有的属性私有化。对每个属性提供 getter 和 setter 方法。如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。建议重写 toString 方法,但这不是必须的。1.2 继承可以理解为,在一个现有类的基础之上,增加新的方法或重写已有方法,从而产生一个新类。每一个类都是在继承。因为在 Java 中存在一个所有类的父类(基类、超类):原创 2021-06-17 14:26:18 · 339 阅读 · 0 评论 -
一个Thread对象能不能调用两次start
执行下面这段程序:package main;/** * @author Floweryu * @date 2021/6/17 10:21 */public class One { public static void main(String[] args) { PrintTime printTime = new PrintTime(); printTime.start(); printTime.start(); } pu原创 2021-06-17 11:35:46 · 1261 阅读 · 0 评论 -
内存分配与回收策略
1. 对象优先在Eden分配大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次MinorGCHotSpot虚拟机提供了-XX:+PrintGCDetails这个收集器日志参数,告诉虚拟机在发生垃圾收集行 为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况。假设设置-Xms20M(堆初始内存)、-Xmx20M(最大堆大小)、-Xmn10M(年轻代大小)这三个参数,其中10MB分给新生代,剩下的10MB分给老年代。-XX:Survivo原创 2021-06-17 09:39:40 · 140 阅读 · 0 评论 -
ThreadPoolExecutor核心设计与实现
1. 总体设计Java中的线程池核心实现类是ThreadPoolExecutor,本章基于JDK 1.8的源码来分析Java线程池的核心设计与实现。我们首先来看一下ThreadPoolExecutor的UML类图,了解下ThreadPoolExecutor的继承关系。ThreadPoolExecutor实现的顶层接口是Executor,顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供Runnable对象,将任务的运行逻转载 2021-06-08 21:15:51 · 388 阅读 · 0 评论 -
两个线程交替打印大小写字母
使用java的两个线程交替打印大小写字母,一个线程打印大写字母,一个线程打印小写字母。1. 只使用synchronized/** * @author Floweryu * @date 2021/6/8 15:46 */public class PrintAa { private static final Object lock = new Object(); private static volatile boolean flag = true; public s.原创 2021-06-08 16:49:48 · 1074 阅读 · 0 评论 -
栈溢出和堆溢出
1. 栈溢出StackOverflowError栈是线程私有的,生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。栈溢出:方法执行时创建的栈帧个数超过了栈的深度。原因举例:方法递归【示例】:public class StackError { private int i = 0; public void fn() { System.out.println(i++); fn();原创 2021-06-07 21:23:51 · 4765 阅读 · 1 评论 -
UDP实现简单聊天
1. 下面程序实现了简单的消息发送和接收发送端import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetSocketAddress;/** * @author Floweryu * @date 2021/原创 2021-05-30 22:31:49 · 175 阅读 · 1 评论 -
UDP实现消息发送与接收
发送端:import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;public class UdpClient { public static void main(String[] args) throws Exception { // 1. 建立udp连接 DatagramSocket socket = new DatagramSocket(原创 2021-05-30 16:32:32 · 465 阅读 · 0 评论 -
TCP实现文件传输
客户端代码:import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.Socket;import java.io.ByteArrayOutputStream;import java.io.File;public class F原创 2021-05-30 14:29:20 · 381 阅读 · 0 评论 -
TCP实现简单聊天
下面是客户端代码,简单的处理了一下异常:Socket socket = null;try { // 1. 知道服务器的地址、端口号 InetAddress serverIp = InetAddress.getByName("127.0.0.1"); int port = 9999; // 2. 创建连接 socket = new Socket(serverIp, port); // 3. 发送消息 OutputStream os = socke原创 2021-05-30 14:28:42 · 114 阅读 · 0 评论 -
设计模式之工厂模式
1. 简单工厂模式该模式通过向工厂传递类型来指定要创建的对象。下面我们使用手机生产来讲解该模式:Phone类:手机标准规范类(AbstractProduct)public interface Phone { void make();}MiPhone类:制造小米手机(Product1)public class MiPhone implements Phone { public MiPhone() { this.make(); } @Overri转载 2021-04-22 17:03:40 · 91 阅读 · 0 评论 -
多线程顺序打印ABC
1. Lock锁方法1.1 基本思路通过ReentrantLock我们可以很方便的进行显式的锁操作,即获取锁和释放锁,对于同一个对象锁而言,统一时刻只可能有一个线程拿到了这个锁,此时其他线程通过lock.lock()来获取对象锁时都会被阻塞,直到这个线程通过lock.unlock()操作释放这个锁后,其他线程才能拿到这个锁。import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;转载 2021-04-20 13:34:11 · 812 阅读 · 0 评论 -
JDK8的新特性
1. 接口改善现在接口里已经完全可以定义静态方法了. 举一个比较普遍的例子就是在java类库中, 对于一些接口如Foo, 都会有一个有静态方法的工具类Foos 来生成或者配合Foo对象实例来使用. 既然静态方法可以存在于接口当中, 那么大多数情况下 Foos工具类完全可以使用接口中的公共方法来代理 (或者将Foos置成package-private).除此之外更重要的就是, Java 8中接口可以定义默认的方法了.举个例子,一个for-each循环的方法就可以加入到java.lang.Iterable中转载 2021-04-20 13:11:21 · 182 阅读 · 0 评论 -
Java创建线程的方式
Java有四种创建线程的方式,分别为实现Runnable接口的run方法,继承Thread类并重写run方法,使用FutureTask方式,利用线程池ExecutorService、Callable、future来实现。1. 前三种创建方式对比采用实现Runnable、Callable接口的方式创见多线程时,优势是:线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而原创 2021-04-20 12:43:31 · 95 阅读 · 0 评论 -
String、StringBuilder与StringBuffer区别
1. 可变性String 类中使⽤ final 关键字修饰字符数组来保存字符串, private final char value[],所以 String 对象是不可变的。在 Java 9 之后,String 类的实现改⽤ byte 数组存储字符串 private final byte[] value⽽ StringBuilder 与 StringBuffer 都继承⾃ AbstractStringBuilder类,在 AbstractStringBuilder中 也是使⽤字符数组保存字符串 ch原创 2021-04-20 12:35:18 · 127 阅读 · 0 评论 -
Java的封装、继承、多态以及重载和重写
1. 面向对象编程三大特性1.1 封装隐藏对象的属性和实现细节,仅对外公开访问方法,控制在程序中属性的读和写的访问级别。封装基本要求把所有的属性私有化。对每个属性提供 getter 和 setter 方法。如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。建议重写 toString 方法,但这不是必须的。1.2 继承可以理解为,在一个现有类的基础之上,增加新的方法或重写已有方法,从而产生一个新类。每一个类都是在继承。因为在 Java 中存在一个所有类的父类(基类、超类):原创 2021-04-20 11:28:03 · 216 阅读 · 0 评论 -
Java内存模型JMM
《Java虚拟机规范》中曾试图定义一种“Java内存模型” (Java Memory Model,JMM)来屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。1. 主内存与工作内存Java内存模型的主要目的是定义程序中各种变量的访问规则,即关注在虚拟机中把变量值存储到内存和从内存中取出变量值这样的底层细节。此处的变量(Variables)与Java编程中所说的变量有所区别,它包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,因为原创 2021-04-15 11:50:34 · 138 阅读 · 0 评论 -
Java内存区域的理解
本文来自《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》一、运行时的数据区域Java虚拟机会在运行时将内存划分为若干个不同的区域,这些区域有各自的用途,创建和销毁时间。下面就分开说说这几个区域的具体内容。1.1 程序计数器(Program Counter Register)程序计数器是一块较小的内存空间,可以看作是当前线程所执行字节码的行号指示器。在Java虚拟机概念模型中,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分.原创 2021-04-15 10:54:36 · 110 阅读 · 0 评论 -
Java线程同步的方法
为什么需要线程同步?java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。1. 同步方法即有synchronized关键字修饰的方法。由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。 public synchronized void save(){}synch原创 2021-04-05 20:50:46 · 168 阅读 · 0 评论 -
Java多线程中start和run方法的区别
start()和run()方法的主要区别在于:当程序调用start()方法,一个新线程将会被创建,并且在run()方法中的代码会在新线程上运行。当直接调用run()方法时,程序并不会创建新线程,run()方法内部的代码在当前线程上运行。【示例】public class DifferentBetweenStartAndRun { public static void main (String[] args) { ThreadTask startThread = ne原创 2021-04-05 16:27:57 · 426 阅读 · 0 评论 -
Java实现单例模式
双重锁实现线程安全的单例模式public class SingleInstance { private volatile static SingleInstance instance = null; private SingleInstance() { } public static SingleInstance getInstance() { if (instance == null) { synchronized(SingleInst原创 2021-04-05 16:04:01 · 123 阅读 · 0 评论 -
Java设计模式总结
1. 什么是设计模式设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。模式:在某些场景下,针对某类问题的某种通用的解决方案。场景:项目所在的环境问题:约束条件,项目目标等解决方案:转载 2021-03-20 20:12:11 · 161 阅读 · 0 评论 -
Java的封装、继承、多态以及重载和重写
1. 面向对象编程三大特性1.1 封装隐藏对象的属性和实现细节,仅对外公开访问方法,控制在程序中属性的读和写的访问级别。封装基本要求把所有的属性私有化。对每个属性提供 getter 和 setter 方法。如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。建议重写 toString 方法,但这不是必须的。1.2 继承可以理解为,在一个现有类的基础之上,增加新的方法或重写已有方法,从而产生一个新类。每一个类都是在继承。因为在 Java 中存在一个所有类的父类(基类、超类):原创 2021-03-19 20:17:30 · 210 阅读 · 0 评论 -
Java并发Map之ConcurrentHashMap
1. ConcurrentHashMap特性ConcurrentHashMap 是线程安全的 HashMap ,用于替代 HashTablepublic interface ConcurrentMap<K, V> extends Map<K, V> {}public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>,原创 2021-03-15 22:26:42 · 752 阅读 · 0 评论 -
Java创建线程的方式
Java有三种创建线程的方式,分别为实现Runnable接口的run方法,继承Thread类并重写run方法,使用FutureTask方式。1. 三种创建方式对比采用实现Runnable、Callable接口的方式创见多线程时,优势是:线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。劣势原创 2021-03-14 10:25:26 · 127 阅读 · 0 评论 -
Java抽象类与接口理解
1. 抽象类1.1 抽象方法抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:abstract void fun();抽象方法必须用abstract关键字进行修饰。1.2 抽象类理解如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。抽象类就是为了继承而存在的。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么原创 2021-03-13 22:56:37 · 241 阅读 · 0 评论 -
Java基本数据类型
1. Java基本数据类型Java基本类型共有八种,其中有4种整形,2种浮点型,1种用于表示Unicode编码的字符单元的字符类型char,1种用于表示真值的boolean类型。JAVA中的数值类型(整型和浮点型)不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。整型可分为:byte、short、int、long浮点类型:float、doublechar类型:charboolean类型:boolean8种数据类型表示的范围如下:byte:1字节,8位,最原创 2021-03-13 22:29:02 · 257 阅读 · 0 评论 -
Java常量池与String常量池理解
1. 先了解JVM内存分布:程序计数器是jvm执行程序的流水线,存放一些跳转指令。本地方法栈是jvm调用操作系统方法所使用的栈。虚拟机栈是jvm执行java代码所使用的栈。方法区存放了一些常量、静态变量、类信息等,可以理解成class文件在内存中的存放位置。虚拟机堆是jvm执行java代码所使用的堆。字符串常量池:直接使用双引号声明出来的 String 对象会直接存储在常量池中。如果不是用双引号声明的 String 对象,可以使用 String 提供的 intern 方String.in原创 2021-03-13 17:59:39 · 641 阅读 · 0 评论