Sayi
Sayi
> java.lang.reflect包是在JDK1.1时引入的,主要提供了一些获取关于类、对象的反射信息的类和接口。通常,它与`java.lang.Class`一起使用。 反射并不神秘,本文对其使用作一个简单的介绍。 ## java.lang.Class类 JDK1.0时引入此类,1.1开始,引入了大量反射的方法。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。 #### forName 通过类的字符串名加载该类 这是获取Class实例的方法之一,通过forName可能加载某一个Class对象,如果找不到该字符串表示的类类,则抛出ClassNotFoundException。如果记得java jdbc编程,最开始会有一行加载驱动的代码: ```java Class.forName("com.mysql.jdbc.Driver"); ``` 这行代码就会加载这个驱动类,并且执行了该类的static区块。 ```java static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't...
> Reflections:运行时解析java元数据。 > [GitHub地址:https://github.com/ronmamo/reflections](https://github.com/ronmamo/reflections) Reflections基于反射和字节码,便于在运行时获取Java元数据,本文就它的使用和源码进行一定解读。 ## Reflections Api 关于如何使用,请参见官网,下面罗列一些提供的Api ```java //获取所有Reader的子类 Set> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Time.class); //获取方法参数名称 List names = reflections.getMethodParamNames(GitHubReader.class.getMethods()[0]); //获取方法使用 Set usage = reflections.getMethodUsage(GitHubReader.class.getMethods()[0]); // 获取资源 Set properties =...
> 本文参考英文原文[Scanning Java Annotations at Runtime](https://bill.burkecentral.com/2008/01/14/scanning-java-annotations-at-runtime/)进行了转述,但是也并非完全一字一句的翻译过来。 当你在开发一个基于注解的框架时,你肯定需要扫描所有使用了特定注解的类,从而初始化你的框架。比如JPA,你需要找到一系列使用了`@Entity`注解的类,从而定义ORM映射。可以使用很多技术在运行时扫描Java注解,本文将对此作探讨。 ## 指定扫描目录 我们需要找到从哪个目录开始扫描,很多框架可以让用户指定目录,比如SpringMVC,通过以下配置(base-package)指定扫描的包名。 ```xml ``` 根据开发环境,我们可以有不同的方法获取扫描目录。 #### 1.Java classpath 通过系统属性`java.class.path`指定扫描目录。 #### 2.classloader 通过`ClassLoader.getResource()` 和 `ClassLoader.getResources()`获取指定资源,从而解析出扫描目录。 ```java ClassLoader cl = Thread.currentThread().getContextClassLoader(); Enumeration urls =...
在并发编程中,我们会遇到一些问题:线程数到底多少合适?如何才能编写出并发访问安全的程序?如果管理这些线程?......理解这些问题有益于我们写出优秀的并发代码,本系列文章将一步步剖析Java并发编程的细节。 本文重点介绍并发基础单元线程,它是进程的一部分。 ## 基础知识:Thread 我们知道,有两个方式去创建线程: 1.**通过继承Thread类** Thread实现了Runnable接口,但是run方法什么都没有做,继承Thread类,重写run方法 ```java public class HelloThread extends Thread { public void run() { System.out.println("Hello from a thread!"); } } ``` 接着我们可以通过start方法来启动线程:`(new HelloThread()).start();`。 2.**实现Runnable接口** Thread类提供了一个Runnable参数的构造器,我们可以通过Runnable对象创建线程。 ```java...
函数式编程是使用像数学里面的函数来编程,函数是给定了输入值,返回结果的运算,函数应该相互独立,不会影响函数外的变量,即无副作用,对于同样的输入值,多次调用函数的结果应该是一致的,即引用透明性。 [Haskell](https://www.haskell.org/)就是这样一门语言,它用数学函数描述这个世界,被称为纯函数编程语言,我们来看看这样一段代码: ```haskell f = 3 ``` 在函数式编程中,函数是中心概念,上面这段代码其实是定义了一个常函数,它并不是一个赋值,因为Haskell中的每个函数都是数学意义上的函数(即“纯粹”),即使是副作用的IO操作也只是对纯代码生成的操作的描述,没有语句或指令。 相比于面向对象编程是在描述“如何做”(命令式编程),函数式编程在描述“做什么”的问题(声明式编程),Java8将函数作为一等公民,我们可以改变下自己的思想,利用函数来编程。 ## 行为参数化、函数对象和策略模式 行为参数化是将行为作为参数传递,在没有函数式编程时,我们已经这样去做了:我们可以在一个对象方法内,调用参数对象的方法。我们来看看对一个List进行排序的代码: ```java List words = Arrays.asList("hello", "sayi", "hi"); words.sort(new Comparator() { public int compare(String str1, String str2) { return...
本文介绍如何结构化执行任务、线程池技术和Future的设计。 > **任务和线程执行分离** :永远不推荐手动调用thread.start()方法去启动线程,线程的执行应该统一去管理,开发者仅仅提供任务的实现即可。 ## Executor Executor是一个定义了如何提交任务的接口,任务通过Runnable接口表示。 ```java public interface Executor { void execute(Runnable command); } ``` 我们来看看Executor的类继承关系图:  ### ExecutorService ExecutorService继承了Executor接口,实现了更多的功能,shutdown方法可以禁止继续提交任务去执行,已经提交的任务还可以继续执行,shutdownNow方法会尝试停止已经提交的任务,invokeAll和invokeAny支持批量执行任务,invokeAny方法当有一个任务成功执行结束时会返回这个任务执行的结果。 相比于Executor提交任务的方式,ExecutorService提供了更多的方式,即一系列重载submit的方法: ```java Future submit(Callable task); Future submit(Runnable task,...
本章重点介绍线程安全的集合类,它们都在java.util.concurrent包下。 ## 阻塞队列:BlockingQueue、BlockingDeque BlockingQueue阻塞队列相对于普通队列来说,提供了额外的操作,: 1. 在队列为空时,take()获取元素的时候会阻塞直到这个队列不为空 2. 在队列满时,put()存储元素的时候会阻塞直到这个队列有剩余的空间 关于队列,参见以前的一篇文章[《Collections(四)Queue》](https://github.com/Sayi/sayi.github.com/issues/45)。 BlockingQueue阻塞队列常用于生产者-消费者模型,比如Google的Volley框架,使用阻塞队列缓存网络请求,使用若干线程从阻塞队列获取网络请求执行,又比如线程池,如果超过了coreSize,就会通过阻塞队列对任务进行排队,工作线程或者新启动线程从阻塞队列取出任务执行。下面的代码是JDK提供的一个示例,生产者进行put操作,消费者执行take操作: ```java class Producer implements Runnable { private final BlockingQueue queue; Producer(BlockingQueue q) { queue = q; } public void run()...
同步控制是指在某些场景下,或允许若干线程执行,或阻塞若干线程场景,前面我们已经了解利用QS state实现各种锁,本文我们学习一些利用AQS state的同步控制类和其它实现的类。 **IMPORTANT:同步控制下,如果允许多个线程同时执行,那么我们还是要避免多线程干涉的问题,比如使用锁。** ## Semaphore 信号量,代表了若干许可,通常场景用来限制某个资源的访问数量,每个线程都将获取许可,如果许可用完了就会阻塞,直到许可被其它线程释放。我们来看看JDK提供的一个示例: ```java class Pool { private static final int MAX_AVAILABLE = 100; private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); public Object getItem() throws...
我们已经知道,synchronized提供了强大的同步功能,volatile提供了稍微弱一点的同步机制,我们也可以通过ThreadLocal和原子类来避免多线程问题,这篇文章将会探讨Java提供更强大的显示锁:Lock,它更加的灵活,在讲解之前,我们先来读一读关于锁的术语: * 共享锁、(排它锁、独占锁、互斥锁) 共享锁表示这个锁可以被多个线程共享,后文中提到的读锁就是一种共享锁,允许多个线程读。排它锁是只有一个线程能占有锁,不允许其它线程获得锁,后文中的写锁就是一个排它锁,不允许任何其它线程读和写,synchronized也是一个排它锁。 * 悲观锁、乐观锁 悲观锁是总会认为并发问题会存在,所以总是会加锁,比如synchronized。而乐观锁假设并发问题不存在,而在更新时才会比较是否发生了并发问题,所以不会加锁,比如CAS机制。 * 重入锁、非重入锁 当前线程可以多次获得同一个锁,就是重入锁,比如synchronized。 * 读写锁 读写锁可以分为读锁和写锁,允许多个线程共享读锁,但是当有写锁被独占时,不允许其它任何线程占有读锁或写锁。 * 偏向锁、自旋锁 这涉及到synchronized底层优化的一些概念,偏向锁升级到轻量级锁等。 * 公平锁、非公平锁 公平锁总是唤醒最先阻塞的线程,所以它是公平的。非公平锁则不一定按照阻塞顺序来唤醒。 锁的种类大多数之间并不是互斥的关系,它们分别从各自的角度去描述这个锁的功能,在数据并发层面,还有行锁、表锁等,在分布式环境下,有分布式锁的概念 接下来,我们将深入研究Lock及其实现。 ## Lock、Conditon Lock是java.util.concurrent.locks包下一个最基本的接口Condition则提供了类似wait/notify机制的await和signal,我们先来看看类图:  正如接口所示,lock和unlock分别是加锁和释放锁,我们必须确保使用完锁会释放锁,典型的Lock使用习惯是通过try-finally来释放锁: ```java Lock lock =...
本文主要针对一些基础算法和底层类(LockSupport)作一个介绍,很多并发的高级特性都是依赖于这些技术。 ## 位操作 位操作作为一个编程技巧或者用二进制思维解决算术问题在许多源码中都出现过,我们不妨回顾一下Java中的位操作。 ### 移位操作 * 左移:符号位不移动,低位丢弃,高位补0。相当于除以2的N次方 * 无符号右移>>>:最高一位为符号位,也会跟着右移,低位丢弃,高位补0。 ### 位运算 * 与&:同时为1,才为1,否则为0。 * 或|:有一个为1则为1,否则为0。 * 非~:1为0,0为1,相反。 * 抑或^:相同为1,相反为0。 ### 示例 基础知识读起来很简单,具体拿来用的时候还是需要掌握一些技巧,我们以一个整型变量为例,无符号的高16位和无符号的低16位分别存储两个整数。 所以第一个问题就是怎么通过位操作获得高16位和低16位的值?可以通过无符号右移16位获得高16位的值,获得低16位就要想办法把高16位变为0,我们可能通过与操作,掩码是0000 0000 0000 0000 1111 1111 1111...