这个问题本来是SO上的一个问答:http://stackoverflow.com/questions/15198319/why-do-we-use-a-datasource-instead-of-a-drivermanager

大致意思是使用DataSource有更好的可扩展性并且更易于维护。
使用DataSource你不需要每次连接都要配置一大段的用户名密码端口,然后才能获得连接去使用数据库。DS方式的话只需要初始化的时候配置一次,每次使用直接拿出连接用就好了。
关于可扩展性,就是DataSource提供连接池,而DM不提供。

JDK8里的描述:

A factory for connections to the physical data source that this DataSource object represents. An alternative to the DriverManager facility, a DataSource object is the preferred means of getting a connection. An object that implements the DataSource interface will typically be registered with a naming service based on the Java™ Naming and Directory (JNDI) API.

先看下原来DM的用法(找了个实习生写的代码,顺便帮他review):

阅读全文 »

HashMap

HashMap使用链表和红黑树来解决Hash冲突,当Hash冲突数比较少时使用链表,当Hash冲突比较多时使用红黑树(Java8新增)。
HashMap的初始大小是16,最大是1<<30,大概是10亿。

This map usually acts as a binned (bucketed) hash table, but when bins get too large, they are transformed into bins of TreeNodes, each structured similarly to those in java.util.TreeMap.

Hashmap一般使用传统的hash桶,如果冲突过多就会转换成使用树节点(TreeNode)来替换hash链表,类似treeMap的结构,
大部分情况下都只是用到普通的hash桶,树节点的hash桶支持更快的查找。

TreeNode的数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
* extends Node) so can be used as extension of either regular or
* linked node.
*/

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}

/**
* Returns root of tree containing this node.
*/

final TreeNode<K,V> root() {
for (TreeNode<K,V> r = this, p;;) {
if ((p = r.parent) == null)
return r;
r = p;
}
}

阅读全文 »

问题

首先明确一个问题,什么是提升性能?所谓的提升性能就是用更少的资源去做更多的事情。
在Java中我们最常使用多线程来提升性能,但是多线程也存在如下问题

  • 线程间的协调
    • 加锁
    • 触发信号
    • 内存同步
      • 有竞争同步,需要关注调优。
      • 无竞争同步,无竞争同步,JVM会通过逸出分析,锁粒度粗化来优化。
  • 上下文切换
    造成: 可运行的线程数 > 处理器的数量
    处理: 分配最小执行时间,分担开销
    开销: 5000-10000个时钟周期(可通过vmstat查看上下文切换次数与在内核中执行时间所占的比例)

  • 线程的创建与销毁

  • 线程的调度
    阅读全文 »

最近在调研spark准备在部门的数据平台上使用spark替换原有的mr。遇到的几个问题解决记录下。
spark相对于传统MR工作流的特色:

  • 查询的管道式执行
  • 没有中间数据会持久化
  • 对表的页数据进行LRU缓存

Spark 真比 mr on hadoop 快吗?

一些对于spark和hadoop不太了解的同学可能会觉得spark和hadoop非此即彼,还有同学问过我spark是基于内存的技术,为什么不直接用spark替换hadoop。
我们处理数据都是会把数据读取到内存上进行操作,而无法直接操作硬盘进行数据的逻辑计算,所谓的spark基于内存的计算只是

  • spark的shuffle操作内存中进行一次而不用像mr那样还要经过一次硬盘。
  • 相比传统的MR工作流中每个job在迭代时都会讲数据存入HDFS,而Spark支持DGA和管道操作,这样就可以让我们执行复杂的工作流而不用将中间数据持久化(除非要进行shuffle)。
    阅读全文 »

首先本文还是为实习生同学解惑用的。某天有个实习生表示对线程池不理解为何要用线程池代替每次产生线程的方式,简单说了几句后,想想干脆整理篇文章好了。

首先按照实习生的想法,来看一段代码

1
2
3
4
5
6
7
8
9
10
11
12
public class ThreadPerTaskWebServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(80);
while (true) {
final Socket socket = ss.accept();
Runnable task = ()-> {
handlRequest(socket);
};
new Thread(task).start();
}
}
}

这段代码为每个连接创建一个线程来处理请求,线程在run方法执行完后终止。在正常负载的情况下,为每个任务创建一个线程能提升串行执行的性能。
但是是否存在问题,当需要创建大量线程的时候:

  • 线程生命周期的开销非常高
  • 资源消耗,活跃线程会消耗系统资源尤其是内存,当线程多于可用处理器的数量,空闲线程会占用许多线程,所以如果CPU已经处于忙碌状态,再创建线程反而会降低性能。
  • 稳定性,在一个平台上创建的线程数是有限的,如果无限创建会突破这些限制则会抛出异常。
    阅读全文 »

Java

源码:

1
2
3
4
5
6
7
8
9
10
11
12
public class RowCounter {
public static void main(String[] args) {
SparkConf conf = new SparkConf();
conf.setMaster("spark://HADOOP-MASTER-153:7077");
JavaSparkContext sc = new JavaSparkContext("local[2]","first spark app",conf);
JavaRDD<String> lines = sc.textFile("C:\\data.txt");
JavaRDD<Integer> lineLengths = lines.map(s -> s.length());
int totalLength = lineLengths.reduce((a, b) -> a + b);
System.out.println(totalLength);
}

}

  • 报错:

    1
    2
    3
    4
    Error:(16, 13) java: 无法访问scala.Cloneable
    找不到scala.Cloneable的类文件
    Error:(19, 45) java: 无法访问scala.Serializable
    找不到scala.Serializable的类文件
阅读全文 »

Scala安装(不是必要的步骤)

下载合适的scala版本

1
wget http://scala-lang.org/files/archive/scala-2.11.8.tgz

解压安装,设置环境变量

1
2
3
4
tar -zxvf scala-2.11.8.tgz -C /usr/local/
vim /etc/profile
export SCALA_HOME=/usr/local/scala
export PATH=$SCALA_HOME/bin:$PATH

测试

1
2
[root@dev-test ~]# scala -version
Scala code runner version 2.11.8 -- Copyright 2002-2016, LAMP/EPFL

阅读全文 »

首先安利一个学习网站:http://www.hubwiz.com/

组合

例子:
将每一行(成员)映射为一个整数值(单词数量),这获得了一个新的RDD。然后在 这个新的RDD上执行reduce动作,找到(返回)了单词数量最多的行。

1
2
scala> textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)
res4: Long = 15

阅读全文 »

最近公司面试实习生搞了几个面试题,前面都是基础考察,后面两个是自己想的。

  • 使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?


  • 简述Java中堆与栈的区别


  • 简述Java实现线程的几种方式


  • 阅读如下代码段,并指出其中存在的问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class MySQLConnection {
    private static Connection mySQLConnection;
    public static Connection getMySQLConnection(){
    Calendar today = Calendar.getInstance();
    int hour =today.get( Calendar.HOUR_OF_DAY);
    if(hour > 8 && hour <23) {
    if(mySQLConnection != null) {
    return mySQLConnection;
    } else {
    try {
    Class.forName("com.mysql.jdbc.Driver");
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/funnystudy","root","123456");
    mySQLConnection = conn;
    } catch (Exception e) {
    e.printStackTrace();
    }
    return mySQLConnection;
    }
    }
    return null;
    }
    }




  • 使用Java处理如下问题。

    现有一张游戏玩家登陆数据表,表结构为 : ‘id’,’name’,’login_date’,现在表中有最近三十天的玩家登陆数据,求出,连续15天的登陆玩家数以及累计15天登陆的玩家数。
    注:连续登录是指,某个玩家在一段时间内,每天都登录游戏,比如1号到15号每天都登录,没错过任何一天,那他连续登录时间是15.一般我们习惯取最大连续登录时间。累计登录是指,某个玩家在一段时间内,登录天数的总和,比如1号 4号 5号登录了,其他时间都没登录,那他这段时间的累计登录天数是3天。