-对于网站客流量统计,可以通过atomic类实现
也可以通过在service前加synchronized 关键字来保证此方法的原子性,但是不推荐这么做,性能太差
-加锁可以保证可见性与原子性,volatile变量只能保证可见性
对此我的理解是:
可见性:所见即所得,为多个线程操作后的最新值。
volatile最好用在原子性操作中,例如A=B而不要放在A++中,因为A=A+1为两步操作
-常用的一些同步对象:
--同步容器:Vector->CopyOnWriteArrayList list相关的同步容器
HashTable->ConcurrentHashMap map相关的同步容器
BlockingQueue FIFO同步队列,支持生产者-消费者设计模式的有界队列
--Synchronizer:
CountDownLatch countDown方法做递减操作,await方法等待递减到0或者线程中断,感觉多人游戏里的准备后开始可以用这个实现
package five;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Driver {
public static void main(String[] args) throws InterruptedException {
int cnt = 5;
CountDownLatch startLatch = new CountDownLatch(1);
CountDownLatch doneLatch = new CountDownLatch(cnt);
Executor executor = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executor.execute(new Worker(startLatch, doneLatch));
}
System.out.println("ready!!");
startLatch.countDown();
System.out.println("done!!");
doneLatch.await();
}
}
package five;
import java.util.concurrent.CountDownLatch;
public class Worker implements Runnable {
private CountDownLatch startLatch;
private CountDownLatch doneLatch;
public Worker(CountDownLatch startLatch,CountDownLatch doneLatch) {
this.startLatch = startLatch;
this.doneLatch = doneLatch;
}
@Override
public void run() {
try {
startLatch.await();
System.out.println("start!!");
doneLatch.countDown();
} catch (Exception e) {
}
}
}
FutureTask 实现了callable接口,Future.get可以取得返回
package five;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class PreLoader {
class Product {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
private FutureTask<Product> task = new FutureTask<>(new Callable<Product>() {
@Override
public Product call() throws Exception {
Product product = new Product();
product.setId(1);
return product;
}
});
public Product run() throws InterruptedException, ExecutionException {
Thread thread = new Thread(task);
thread.start();
return task.get();
}
}
Semaphore 一个计数信号量,aquire()获得一个许可,release()添加一个许可,如果没有可用许可,那么aquire会被阻塞,直到有可用的为止
粗略实现数据连接池:
package five;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
public class DataSource {
class Con{
private boolean userd;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isUserd() {
return userd;
}
public void setUserd(boolean userd) {
this.userd = userd;
}
public boolean equals(Con con) {
if (this.getId() == con.getId() && this.userd == con.isUserd()) {
return true;
}
return false;
}
}
private Semaphore semaphore;
private List<Con> cons = new ArrayList<Con>();
public DataSource(int conNum) {
semaphore = new Semaphore(conNum);
for (int i =0; i < conNum; i++) {
Con con = new Con();
cons.add(con);
}
}
public Con getConnection() throws InterruptedException {
semaphore.acquire();
return getNextAvaCon();
}
public void putConnection(Con con) {
if (markAsUserd(con)) {
semaphore.release();
}
}
private synchronized Con getNextAvaCon() {
for (int i = 0; i < cons.size(); i++) {
Con con = cons.get(i);
if (!con.isUserd()) {
con.setUserd(true);
return con;
}
}
return null;
}
private synchronized boolean markAsUserd(Con con) {
for (int i = 0; i < cons.size(); i++) {
Con conIndex = cons.get(i);
if (conIndex.equals(con)) {
if (conIndex.isUserd()) {
cons.get(i).setUserd(false);
return true;
} else {
return false;
}
}
}
return false;
}
}
6.executor框架系列
Executors.newFixedThreadPool 创建一个定长的线程池
Executors.newCachedThreadPool创建一个可缓存的线程池
Executors.newScheduledThreadPool 创建一个定长的线程池,并支持定时以及周期性的任务,jdk1.5后 取代Timer.
ExecutorService 生命周期的三种状态:运行,关闭,终止
shutdown()执行以前提交的任务顺序关闭
shutdownNow()停止所有正在执行的活动任务。
ExecutorCompletionService可以以BlockingQueue<Future>作为参数,返回一些列执行完后的值
线程未捕获异常的处理:
由UncaughtExceptionHandler和ThreadFactory处理,其中线程池中可以传入自定义的ThreadFactory进行处理。
线程池通用的构造函数
public ThreadPoolExecutor (
int corePoolSize //核心池大小
int maximumPoolSize, //最大池的大小
long keepAliveTime, //存活时间
TimeUnit timeUnit, //时间单位
BlockingQueue<Runnable> workQueue, //工作线程
ThreadFactory factory //线程工程,对线程进行自定义加工
RejectedExecutionHandler hanlder //饱和策略
) {...}
对于线程池的三个钩子方法,我们可以自定义一些统计信息或者日志信息。我们可以用ThreadLocal在beforeExecute 和afterExecute之间进行传输数据
以下为自定义线程池
package eight;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class TimingThreadPoolExecutor extends ThreadPoolExecutor {
private ThreadLocal<Long> startTime = new ThreadLocal<Long>();
private AtomicLong taskNum = new AtomicLong();
private AtomicLong totalTime = new AtomicLong();
public TimingThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
// TODO Auto-generated constructor stub
}
protected void beforeExecute(Thread t, Runnable r) {
startTime.set(System.nanoTime());
super.beforeExecute(t, r);
}
protected void afterExecute(Runnable r, Throwable t) {
taskNum.incrementAndGet();
totalTime.addAndGet(System.nanoTime() - startTime.get());
super.afterExecute(r, t);
}
protected void terminated() {
long avgTime = totalTime.get()/taskNum.get();
super.terminated();
}
}
调节共享对象访问机制有 synchronized 、volatile、ReentranLock
死锁恢复:用lock的trylock方法指定超时时间
读写锁:能够被多个读者访问,只能被一个写着访问,两者不能同时进行。ReadWriteLock
ReentranLock与semaphore互相实现的代码:
package footeen;
/**
* 用lock实现semaphore*/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SemaphoreOnLock {
private final Lock lock = new ReentrantLock();
private int avalibleNum;
private final Condition condition = lock.newCondition();
public SemaphoreOnLock(int avalibleNum) {
lock.lock();
try {
this.avalibleNum = avalibleNum;
} finally {
lock.unlock();
}
}
public void aquire() {
lock.lock();
try {
if (avalibleNum <= 0) condition.await();
--avalibleNum;
} catch (Exception e){
} finally {
lock.unlock();
}
}
public void release() {
lock.lock();
try {
++avalibleNum;
condition.signal();
} finally {
lock.unlock();
}
}
}
package footeen;
import java.util.concurrent.Semaphore;
/**
* 用信号量实现lock*/
public class LockOnSemaphore {
private final Semaphore semaphore = new Semaphore(1);
public void lock() {
try {
semaphore.acquire();
} catch (Exception e) {
}
}
public void unlock() {
semaphore.release();
}
}