2015年6月

tomcat 配置在linux上, 机器重启后 自动启动

#!/bin/bash

### BEGIN INIT INFO
# Provides:        tomcat7
# Required-Start:  $network
# Required-Stop:   $network
# Default-Start:   2 3 4 5
# Default-Stop:    0 1 6
# Short-Description: Start/Stop Tomcat server
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin

start() {
 sh /opt/apache-tomcat-7.0.59/bin/startup.sh
}

stop() {
 sh /opt/apache-tomcat-7.0.59/bin/shutdown.sh
}

case $1 in
  start|stop) $1;;
  restart) stop; start;;
  *) echo "Run as $0 <start|stop|restart>"; exit 1;;
esac

chmod 755 /etc/init.d/tomcat7
update-rc.d tomcat7 defaults

另外一种写法

 #!/bin/sh
 #tomcat auto-start
 case $1 in
        start)
            sh /opt/apache-tomcat-7.0.59/bin/startup.sh;;
        stop)
            sh /opt/apache-tomcat-7.0.59/bin/shutdown.sh;;
        restart)
            sh /opt/apache-tomcat-7.0.59/bin/shutdown.sh
            sh /opt/apache-tomcat-7.0.59/bin/startup.sh;;
        *)
            echo 'Usage:tomcat7 start|stop|restart';;
    esac
    exit 0

从这里抄过来的: http://askubuntu.com/questions/223944/how-to-automatically-restart-tomcat7-on-system-reboots

Java Executor Framework

Executor Framework

Executor framework 以Executor接口为核心, 有ExecutorService 和 ScheduledExecutorService 2 个子接口, 提供了线程创建, 销毁的快捷方式, 并且线程可以做到复用.

Runnable VS Callable

  1. Callable 提供的call() 方法, 可以异步返回结果, 可以throw checked Exception;
  2. ExecutorService 接口可以通过 submit, invokeAny, invokeAll 去执行Callable 接口, 返回Future.

ExecutorService

shutdown() 和 shutdownNow() 的区别在于是否执行pending的task.
如果当前线程要等待ExecutorService的线程都执行完, 必须调用shutdown / shutdownNow, 然后调用
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException.
invokeAny() 方法返回最快的一个Task 结果, 如果第一个有Exception, 一次找后面比较快的, 如果都有异常, 则返回异常.

Future

ExecutorService 的 submit(), invokeAll(), invokeAny() 都返回Future对象, 它能track Callable 执行的状态, 能cancel Callable.

FutureTask

FutureTask 实现了Runnable, Future, RunnableFuture 接口.
因为实现了Runnable接口, 所以可以被Thread, ExecutorService执行.
因为实现了Future 接口, 所以可以track status, 可以被cancel;
构造函数可以封装 Runnable 和 Callable.

一张图总结一下:
box-598143524220884.jpg

线程同步工具类[2]

Phaser

适用于分阶段的线程同步. 可以在构造时设置一个初始的参与的线程个数, 也可以后边通过方法注册与注销. 所以它的生命周期内参与的线程数是可以变化的. 当其中参与的线程到达某个phase的确认点之后, 可以选择等待,或直接继续, 或者不参与到下一个phase.
Phaser内部维护phase的数值, 记录当前那些phase到达的数量, 但是不会维护参与者的信息. 这里有个很重要的概念是: Phase 并不管有多少线程, 它只管每个阶段达到方法被调用的次数, 只要被调用的次数足够, 它就到下一阶段, 典型的是Phaser的注册数有N个, 但是这N全是一个线程在调用arrive() 方法. 当然如果是要求多个同步, 一般是多个线程调用arriveAndAwaitAdvance(). 这个phase 数值从0 开始, 当要求的参与者都到达之后加一.

public int arrive() 方法不会等待其他参与者, 当此线程下次调用相关的arrive*()方法的时候, 有可能还是当前phase, 是当前phase的到达者加一. 如
public static void main(String[] args) {
Phaser p = new Phaser(3);

    System.out.println(p.arrive());
    System.out.println(p.arrive());
    System.out.println(p.arrive());
    
    System.out.println(p.arrive());
    System.out.println(p.arrive());
    System.out.println(p.arrive());
    p.forceTermination();
}

public int arriveAndAwaitAdvance() 方法等同于awaitAdvance(arrive()), 和 CyclicBarrier的await() 方法类似.

不等待: arrive();
不等待并且使参与者减少一个: arriveAndDeregister()
等待这一个phase结束并且使参与者减少一个: awaitAdvance(arriveAndDeregister())

public int awaitAdvance(int phase) 这个方法很容易让人迷糊, 以为它会一直等待第N phase, 其实不然, 只要是当前phase 和N 不相等, 就立马返回. 所以, 如果你想真正的等待第N phase, 那么你可能需要这么做:
while (p.getPhase() < N) {
p.awaitAdvance(p.getPhase()); // 前提是你N之前都没注册
}
//此处已到N或者N+

protected boolean onAdvance(int phase, int registeredParties) 方法是在所有参与者到达后, 下一phase 开始之前执行的, 类似CyclicBarrier 的Action Command. 这个方法可以用来override 去替换一些特定的Action. 如果返回值是true, 则本phase 是最后一个阶段.
如果Phaser 已经终止, 则后面的await都会立马返回.

Exchanger

在一个同步点, 2个线程彼此通过Exchanger交换数据.

线程同步工具类[1]

Low level synchronize

Java 提供的Low level 同步方式主要有 synchronize 关键字 和 Lock 的实现类.
Lock的实现类主要有 ReentrantLock 和 ReentrantReadWriteLock.ReadLock 和 ReentrantReadWriteLock.WriteLock;
使用Object的wait(), notify() 和notifyAll() 方法, 也可以实现同步.

High level synchronize

Java 提供的high level 同步方式主要有
Semaphore, CountDownLatch, CyclicBarrier, Phaser, Exchanger.

Semaphore

Semaphore一般用来对共享资源的限制访问, 通过构造函数参数设置共享资源的总量, 通过acquire() 获得访问权限, 通过release() 释放已经获得的权限.
通过设置fair参数, 可以设置是否可以公平获得.
当acquire() 不能立即得到时, 当前线程会挂起, 直到获得或者被interrupted . acquire()的变种有:
void acquire(int permits);
void acquireUninterruptibly();
void acquireUninterruptibly(int permits);
boolean tryAcquire();
boolean tryAcquire(int permits);
boolean tryAcquire(int permits, long timeout, TimeUnit unit);
boolean tryAcquire(long timeout, TimeUnit unit);
release() 方法也有变种 release(int), 一次release 多个permit.
当permit 只有1的时候, 通常被称之为Binary Semaphore, 与很多Lock机制类似.
还提供了一些其他实用方法去check semaphore的当前状态, 比如: availablePermits(), getQueuedThreads(), getQueueLength(), isFair().

CountDownLatch

CountDownLatch 是一个非常简洁的线程同步实用工具, 初始设置等待的事件数为N (构造函数设置), 在等待的线程通过await()方法被block住, 直到有足够的其它线程调用Latch的countDown() 方法, 一直到count down 到0.
并不需要有N个线程调用countDown() 方法, 也许更多, 也许更少, 一个线程调用countDown方法之后, 不会被block, 会继续运行(与CyclicBarrier不同), 它有可能多次调用countDown() 方法.
同时, 也不一定只有一个线程在await(), 可能有多个线程同时在等待.
await() 的另外一个变种是只wait固定的时间await(long timeout, TimeUnit unit);
count数不能reset, 只能在构造函数时传入, 一旦count down 到0, 后续的await() 线程return immediately, 不会被block.

CyclicBarrier

N个线程等待一个同步点. 每个线程在同步点的代码处调用await()方法, 同时被block住, 直到有N个线程都调用了await()方法, 则所有在此同步点被block的线程被release. 被release之后, 这个Barrier可以被重复利用, 只要调用reset()方法, 就可以再次被利用, 所以冠以 Cyclic.
CyclicBarrier可选设置一个Runnable Command, 当N个线程都达到同步点之后, 并且在这些线程被release 之前, 这个Runnable command 被执行, 可以做一些求和, 总结之类的事情.
await() 有个变种, 可以设置最长等待时间 public int await(long timeout, TimeUnit unit);
await() 的返回值是线程到达barrier的index, (parties -1) 是第一个, 0 代表最后一个. 如果设置了Runnable Command, 那么最后一个到达的去执行这个Runnable Command. 如果你想设置第一个到达的去执行, 可以不要设置到 CyclicBarrier的构造函数中, 而是判断 await() 方法的返回值(arrival index).
若任何等待线程在等待期间被interrupt, 则所有线程抛出 InterruptedException;
若Barrier 被reset, 则抛出 BrokenBarrierException.
若设置的 timeout 时间超时, 则抛出 TimeoutException.
如果有线程timeout 或者被 interrupt, 或者Barrier Action 发生异常, 都会导致Barrier 变成 Broken 状态.

Java 线程同步 Synchronized 和 Lock

synchronized关键字

synchronized关键字可以作用于代码块,也可以作用于方法声明. 若作用于代码块, 必须显式指明使用那个对象或类的monitor锁. 若作用于方法: 方法是static, 则使用类的monitor, 否则使用对象实例的monitor.
若已获得某对象或类的monitor, 可再次进入该对象或类monitor 作用的块或方法.
被synchronized的语句要尽量少, 以提高性能;
若某线程已经通过synchronized获得A的monitor, 又获得B的monitor,

synchronized与 wait(), notify(), notifyAll()

wait(), notify(), notifyAll()必须在获得同一对象实例或类的的monitor的 synchronized的语句中, 否则JVM会抛出IllegalMonitorStateException.
当wait() 方法被调用之后, 当前线程释放该对象或实例的monitor, 并且挂起, 其它等待该monitor的线程获得该monitor, 进入被保护的synchronized语句运行, 直到有获得同样monitor的线程调用notify() 或notifyAll() 方法, 并且释放该monitor, 挂起的线程才有可能恢复运行.
另外 wait(), notify(), notifyAll() 方法都会抛出 InterruptedException, 要注意处理;wait() 一般处在一个while循环中, 每次醒来都去check一下当前的条件是不是已经被满足.

Intrinsic Locks and Synchronization 内置锁和synchronized

Java的synchronized是建立在所有对象内置的一个内置锁. 在一般的教程或API中一般称之为 intrinsic lock or monitor lock, 有时候也简单的称之为 monitor.
这里有更详细的说明: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

多个synchronized 的锁获得与释放顺序

在JDK Lock的文档看到这么一句讲synchronized锁的: when multiple locks are acquired they must be released in the opposite order. 其实锁并不需要这个顺序, 只不过这是synchronized的语句结构造成的, 每个synchronized的语句都有一对大括号用来显示指明起锁的代码范围, 词法结构造成了这个获得与release的顺序. 所以也就有了接下来的这句: all locks must be released in the same lexical scope in which they were acquired.
这也是synchronized与Lock的重要区别. 当然这种结构也使这种锁更简单, 不容易出错.

Lock 接口 的 non-blocking 特性

Lock 相对于synchronized的最大优点是, 可以尝试去获得Lock, 而不是一直等待:
boolean tryLock() //试图获得, 当lock free 的时候便可以获得;
boolean tryLock(long time, TimeUnit unit) // 在给定时间内尝试获得, 并且线程没被interrupted.
void lockInterruptibly() // 尝试获得, 除非当前线程被interrupted
同时Lock 也可以通过与之关联的Condition 类实现了 wait/notify 机制;

Lock 相对于synchronized的其它特性

获得锁的顺序: 公平锁, 不公平锁;
non-reentrant : synchronized一定是reentrant的, Lock 可以做到不允许reentrant (参考具体实现);
死锁检测:

Lock Condition

Lock取代了synchronized关键字, Condition取代了synchronized需要的内置锁.
Object 的wait()/notify()/notifyAll() 方法依赖对象或类的内置锁实现等待和唤醒, Lock的子类则通过Condition实现线程的等待和唤醒, Condition有对应的await(), signal() 方法.
Object的wait()/notify()/notifyAll() 方法只能依赖该对象的唯一内置锁, 而Lock可以依赖多个Condition, 同一把锁, 有多个开始等待和唤醒的条件, 那么就可以实现根据不同的条件, 唤醒正在等待这把锁的多个线程中特定的线程, 从而可以实现唤醒的顺序, 也提高了系统的效率.
尽管Condition对象也有内置锁, 但它的现实与之内置锁, 没有任何关系.

ReentrantLock

ReentrantLock 可以设置公平性(fair) 参数. 同时也提供了一些有用的方法去监控当前Lock的状态, 如: isLocked(), getLockQueueLength(),isHeldByCurrentThread(), getHoldCount(),getWaitingThreads(Condition condition) 等.

ReadWriteLock

读写锁允许多线程对共享资源的并发访问, 它有读锁和写锁两把锁, 读锁允许同时有多个线程读, 不能有写锁被Lock, 写锁只允许同时有且仅有一个写操作获得锁.
数据库表的操作是一个典型的读写锁的例子.
读写锁的性能取决于读操作和写操作的频率对比, 以及读操作写操作的单词操作时长.