重温生产者和消费者模型

生产者和消费者模型,主要解决的是数据的同步问题,生产者将数据放置一个存储区域,然后消费者过来取数据。这种模式类似于一个中间件,可以使得生产者不需要关心消费者什么时候来拿数据,同时在这种模式下,还可以控制两边的处理速率,避免数据的丢失。

下面以 Java 为例,来写一个生产者和消费者模型。

当队列满了的时候,生产者自己进行阻塞。而当消费者发现队列为空,则将自己阻塞。

所以要实现这个生产者消费者模型,首先必须有以下条件:

  1. 生产者或者消费者必须支持可阻塞
  2. 在多线程的情况下,必须保证并发安全(即插入不能产生数据错误),取数据不可以重复取
阅读更多

Thread.sleep(0)-vs-Thread.yield()

简介

Thread.sleep(long)yield() 都表示的是让出当前线程的 CPU 时间片,两者在执行的时候,都不会去释放自己已经持有的锁。

多线程

在现代的处理器中,以 4核心CPU 为例,这表示在同一个时刻,只会有 4 个线程在并行执行,而在每一个核心内部,多个线程其实是顺序执行的,它们的执行顺序依赖于线程的调度算法。

线程调度算法

阅读更多

ThreadLocalMap 简单分析

ThreadLocal

在使用多线程的时候,如果需要保存一份线程自己私有的一部分变量,避免其他线程污染这个变量的话,一般都会自己手动 new 一个 ThreadLocal,如下代码:

1
2
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("test");

当需要在某一刻使用这个变量的时候,只需要手动调用下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
threadLocal.get();
```

## ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的一个静态内部类,每一个线程在创建的时候都会有这个 ThreadLocalMap 变量,它的作用就是存储每一个通过 `threadLocal.set()` 方法存入的值,本质上也是一个HashMap。

先看下它的一个内部类:
### Entry
不同于 WeakHashMap 是继承自 HashMap 的Entry,ThreadLocalMap 的Entry 则是自己的一个内部类。
```java
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
阅读更多

阿里云SDK使用代理的一个坑

由于项目中需要使用阿里云的短信平台,所以直接引用了最新的SDK,版本号为 4.5.1。但是由于机器在内网环境,如果需要访问外部网络的话,需要代理机器。于是去看下 阿里的SDK 官方文档,如何支持代理访问,于是找到以下内容:

坑就坑在这个文档里面的设置方法,设置了并没有什么用。于是自己研究了下这种设置为什么不生效。

System.setProperty

这个命令和在启动参数中加 -DXXX=XXX 是一样的效果,例如:

阅读更多

记一次parallelStream错误使用导致的NullPointerException

parallelStream

在 Java8 中,新增了一个很有用的功能就是 ,这个功能可以使我们可以快速的写出优雅的代码,其中 stream 是一个串行流(说法可能有误…就是不会采取多线程来进行处理)。还有一种就是 parallelStream 采用 ForkJoinPool 来实现并发,加快执行效率。

所以在使用 parallelStream 的时候一定要注意线程安全的问题,首先看一段代码:

在这段代码中,是首先判断 dataListList 里面对象的 name 属性是否是偶数,是的话则添加至偶数List,反之则添加至奇数List。

然后开始测试这段代码:

阅读更多

WeakHashMap的实现原理

简介

什么是WeakHashMap

WeakHashMap实现了 Map 接口,属于 Java 集合中的一员,其用法几乎和 HashMap 一致,但是由于它的 Entry 还继承了 WeakHashMap ,因此导致它的这个 Entry 在触发 FullGc 的时候是有可能可以被回收的。

以下测试,JVM参数统一为:-Xmx64M -Xms64M -XX:+PrintGCDetails

首先上一段代码:

阅读更多

代理模式之JDK为什么需要实现接口(下篇)

前言

在上篇主要介绍了 JDK 动态代理执行的一些流程,通过 Proxy 类来实现生成新的代理类,在这一篇主要讲的是 Proxy 是如何来生成以及缓存生成的代理类

二级缓存

在上一篇的结尾提到过了一个map,其结构如下:

ConcurrentMap<Object, ConcurrentMap<Object, Supplier>>

阅读更多

代理模式之JDK为什么需要实现接口(上篇)

简介

首先代理模式分为静态代理和动态代理,由于JDK采用的是动态代理,所以静态代理在这里不再介绍。

动态代理

JDK动态代理

首先JDK的动态代理要求真实的对象必须实现一个接口,而代理类则实现InvocationHandler接口来完成动态代理。如下代码:

阅读更多

重温Java中String

本文的内容都是基于 JDK1.8 来写的,主要是复习下 String 类的设计。

简介

String 是一个用于存储字符串的类,其内部是通过 char 数组来实现,在 Java 中,1byte = 8bit,1char = 2byte, 所以在 Java 中,String 的code point是16位。
String 类是由 final 关键字来修饰的,因此表明该类不可以被继承,同时 String 又实现了 Serializable、Comparable、CharSequence接口,表明 String 可以被序列化,以及使用cpmpareTo来比较两个字符串的值。

字符集编码

内码

阅读更多

java信号量的简单了解

在Java语言里面,Semaphore 的作用是可以控制对于同一个临界资源,允许多少个线程同时执行。
当线程执行到临界区域的时候,需要先向 Semaphore 申请一个令牌,此时 Semaphore 会判断现有的的令牌是不是小于0,如果小于0,则阻塞当前线程,直至有线程将令牌归还回来。

申请到了permits

如果一个线程直接申请到了permits,则是直接通过CAS操作将 state 减一即可,然后线程继续执行。

无法申请到permits

当无法申请到 Semaphore 的 permits 的时候,则会将当前的线程进行阻塞,直到有线程执行完毕,释放了 permit。

阅读更多