【整理】Java并发程序设计
来源:互联网 发布:mac桌面日历软件 编辑:程序博客网 时间:2024/04/27 17:20
1.无论任何方式启动线程,都要给一个名字,对排错监控有用
public class Name {public void method1(){Thread thread = new Thread("name"){public void run() {//doxxx}};thread.start();}public void method2(){class MyThread extends Thread{public MyThread(){super("name");}public void run(){//doxxx}}MyThread thread = new MyThread();thread.start();}public void method3(){Thread thread = new Thread(){public void run() {//doxxx}};thread.setName("name");thread.start();}public void method4(){Task task = new Task() {public void run() {// TODO Auto-generated method stub}public void cancel() {// TODO Auto-generated method stub}};Thread thread = new Thread(task);thread.setName("name");thread.start();}}
2.要响应线程中断 Thread.interrupt()
public class Response {public void method1(){Thread thread = new Thread("name"){public void run() {//doxxxfor(;;){//doxxx();if(Thread.interrupted()){break;}}}};thread.start();}public void method2() throws InterruptedException{if(Thread.interrupted()){throw new InterruptedException();}}public void method3(){Thread thread = new Thread("name"){public void run() {//doxxxfor(;;){try{method2();}catch (InterruptedException e) {break;}catch (Exception e) {}}}};thread.start();}}
3.ThreadLocal 线程局部变量
*功能:使用该变量的线程都提供一个变量值的副本,而不会与其他线程的副本冲突
* 相当于每个线程都拥有该变量
*注:使用ThreadLocal一般声明在静态变量中,如果不断创建不调用remove()会造成内存泄露
public class Log {private static ThreadLocal tsLogCollection = new ThreadLocal(); // 加入一个log public static void println(String s) { getTSLog().println(s); } // 关闭log public static void close() { getTSLog().close(); } // 取得线程特有的log,注意每一个线程都有一个副本的log,所以无论怎样调用TSLog的内容,都不会出现数据出错的现象 private static TSLog getTSLog() { TSLog tsLog = (TSLog)tsLogCollection.get(); //如果线程是第一次呼叫,就建立新挡案并登陆log if (tsLog == null) { tsLog = new ThreadLocalPratice().new TSLog(Thread.currentThread().getName() + "-log.txt"); tsLogCollection.set(tsLog); } return tsLog; }}public class ThreadLocalPratice {public static void main(String[] args) { new ThreadLocalPratice().new ClientThread("A").start(); new ThreadLocalPratice().new ClientThread("B").start(); new ThreadLocalPratice().new ClientThread("C").start(); } class TSLog { private PrintWriter writer = null; // 初始化writer字段 public TSLog(String filename) { try { writer = new PrintWriter(new FileWriter(filename)); } catch (IOException e) { e.printStackTrace(); } } // 加入一笔log public void println(String s) { writer.println(s); } // 关闭log public void close() { writer.println("==== End of log ===="); writer.close(); } }class ClientThread extends Thread {public ClientThread(String name) { super(name); } public void run() { System.out.println(getName() + " BEGIN"); for (int i = 0; i < 10; i++) { Log.println("i = " + i); try { Thread.sleep(100); } catch (InterruptedException e) { } } Log.close(); System.out.println(getName() + " END"); } }}
4.任务的提交者和执行者
* Executor-为了并发执行任务,用来执行任务的实现;任务提交者不再需要创建管理线程。
* java.util.concurrent.Executors 是Executor的工厂类,可以创建需要的Executor。
5.任务提交者和执行者之间的通讯手段 Futrue
* get(阻塞至任务完成),cancel,get(timeout)(等待一段时间)等
* 也用于异步变同步的场景
public class Future {public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException{Future test = new Future();test.method();}public void method() throws InterruptedException, ExecutionException, TimeoutException {ExecutorService executor = Executors.newSingleThreadExecutor();//Task Executor 有两种任务:Runnable Callable(需要返回值)Callable<Object> task = new Callable<Object>(){public Object call() throws Exception {Thread.sleep(5000);Object result = "测试Future";return result;}};//Task Submitterjava.util.concurrent.Future<Object> future = executor.submit(task);//Object object = future.get();//等待任务结束返回结果,如果任务出错会有ExecutionException异常Object object = future.get(3, TimeUnit.SECONDS);//等待3秒,任务执行超时后会报TimeoutException异常System.out.println(object);}}
6.阻塞队列
* 常用的并发数据结构,常用语生产者消费则模式
* producer:blockingQ.put(Object);//队列满时阻塞
* consumer:for(;;){blockingQ.take();//队列空时阻塞}
*
* 三种常用队列:ArrayBlockingQueue LinkedBlockingQueue SynchronousQueue
* (1)使用BlockingQueue时尽量不要使用Queue的方法,否则就没了Blocking的特性;
* BlockingQueue中使用put、take;而非offer、poll(Queue的方法);如果要用也要使用等待时间参数的offer、poll(BlockingQueue方法)
* drainTo批量获取其中的内容,减少锁的次数
public class Queue {final BlockingQueue<Object> blockQ = new ArrayBlockingQueue<Object>(10);Thread thread = new Thread("name"){public void run(){for(;;){try {Object object = blockQ.take();//等到有数据才继续//Object object = blockQ.poll();错误,不等待就会直接返回//Object object = blockQ.poll(1,TimeUnit.SECONDS);if(object==null){continue;}//正确,防止死等//handle(object);} catch (InterruptedException e) {break;}catch (Exception e) {//handle Exception}}}};}
7.实现一个简单的阻塞队列-学习并发知识
*
* synchronized是Lock的简化版本,synchronized代表Lock只对应一个Condition。
* jdk5,synchronized比Lock慢很多,jdk6效率差不多。
* 不要在Lock、Condition上使用wait、notifyAll、notify方法。
public class PracticeQueue {/** *(1)未取得锁就执行wait、notify或notifyAll就会抛异常 */class Practice1{private Object notEmpty= new Object();private Queue<Object> LinkedList = new LinkedList<Object>();public Object take() throws InterruptedException{synchronized (notEmpty) {if(LinkedList.size()==0){notEmpty.wait();//要执行wait操作,必先去的对象的锁;执行wait操作之后,锁会释放。被唤醒前,需要先获得锁。}return LinkedList.poll();}}public void offer(Object object){synchronized (notEmpty) {if(LinkedList.size()==0){notEmpty.notifyAll();//要执行notify或notifyAll操作,必须先取得该对象的锁。}LinkedList.add(object);}}}/** *(2) */class Practice2{private Object notEmpty= new Object();private Object notFull= new Object();private Queue<Object> LinkedList = new LinkedList<Object>();private int maxlength=10;public Object take() throws InterruptedException{synchronized (notEmpty) {//分别需要对notEmpty、notFull加锁if(LinkedList.size()==0){notEmpty.wait();}synchronized (notFull) {if(LinkedList.size()==maxlength){notFull.notifyAll();}return LinkedList.poll();}}}public void offer(Object object) throws InterruptedException{synchronized (notEmpty) {//分别需要对notEmpty、notFull加锁if(LinkedList.size()==0){notEmpty.notifyAll();}synchronized (notFull) {if(LinkedList.size()==maxlength){notFull.wait();}LinkedList.add(object);}}}}/** *(3) */class Practice3{private Lock lock = new ReentrantLock();//一个锁可以创建多个Conditionprivate Condition notEmpty = lock.newCondition();private Condition notFull = lock.newCondition();private Queue<Object> LinkedList = new LinkedList<Object>();private int maxlength=10;public Object take() throws InterruptedException{lock.lock();try{if(LinkedList.size()==0){notEmpty.await();//要执行await,必须先取得该Condition的锁。执行完await后,锁会释放。被唤醒之前,必须先获得锁。}if(LinkedList.size()==maxlength){notFull.signalAll();}return LinkedList.poll();}finally{lock.unlock();}}public void offer(Object object) throws InterruptedException{lock.lock();try{if(LinkedList.size()==0){notEmpty.signalAll();//在执行signal或者signalAll操作,都必须先取得该对象的锁}if(LinkedList.size()==maxlength){notFull.await();}LinkedList.add(object);}finally{lock.unlock();}}}}
8.使用AtomicInteger
*硬件提供的原子操作指令实现,开销小速度快。
*此外还有AtomicBoolean AtomicLong AtomicReference
public class Atomic {class One{private volatile int count =0;public synchronized void increment(){//要线程安全须加锁count++;}public int getCount(){return count;}}class Two{private AtomicInteger count = new AtomicInteger();public void increment(){count.incrementAndGet();//不需要加锁也能够线程安全}public int getCount(){return count.get();}}}
9.使用Lock-Free算法
public class LockFree {//////////////////////////////////////// 一 ///////////////////////////////////////class Count1{private volatile int max=0;public synchronized void set(int value){//要线程安全需要加锁if(value>max){max=value;}}public int getMax(){return max;}}class Count2{//Lock-Free算法,不需要加锁。通常都是三部分组成private AtomicInteger max = new AtomicInteger();public void set(int value){for(;;){//(1)循环int current = max.get();if(value>current){if(max.compareAndSet(current, value)){//(2)CAS false表示max的实际值和预期值(current)不相等。value(更新的新值)break;//(3)回退}else{continue;}}else{break;}}}public int getMax(){return max.get();}}//////////////////////////////////////// 二 ///////////////////////////////////////class BeanManager1{private Map<String, Object> map = new HashMap<String, Object>();public Object get(String key){synchronized(map){Object bean = map.get(key);if(bean==null){map.put(key, new Object());bean = map.get(key);}return bean;}}}class BeanManager2{private ConcurrentMap<String, Object> map = new ConcurrentHashMap<String, Object>();public Object get(String key){Object bean = map.get(key);if(bean==null){map.putIfAbsent(key, new Object());//使用ConcurrentMap,避免直接使用锁bean = map.get(key);}return bean;}}}
10.更新数据库-乐观锁(Lock-free算法)、悲观锁)
public class DbUpdate {//////////// 乐观锁 //////////////class SequenceDao extends SqlMapClientDaoSupport{public boolean compareAndSet(String name,int value,int except){Map<String, Object> parameters = new HashMap<String, Object>();parameters.put("name", name);parameters.put("value", value);parameters.put("except", except);//update t_sequence set value=#value# where name=#name# and value=#except#int updateCount = getSqlMapClientTemplate().update("Sequence.compareAndSet", parameters);//通过updateCount来实现compareAndSetreturn updateCount==1;}}/** * 三个部分:循环 CAS 回退 */class SequenceService{SequenceDao dao;@Transactional(propagation=Propagation.NOT_SUPPORTED)//乐观锁时必须使用public synchronized void increment(String sequenceName){for(;;){int value = dao.getValue(sequenceName);if(dao.compareAndSet(sequenceName, value+1, value)){break;}}}}////////////悲观锁 //////////////class SequenceDao2 extends SqlMapClientDaoSupport{public int getValueForUpdate(String name) {//select value from t_sequence where name=#name# for updatereturn (Integer)getSqlMapClientTemplate().queryForObject("Sequence.getValueForUpdate",name);}public void compareAndSet(String name,int value){Map<String, Object> parameters = new HashMap<String, Object>();parameters.put("name", name);parameters.put("value", value);//update t_sequence set value=#value# where name=#name# getSqlMapClientTemplate().update("Sequence.set", parameters);}}class SequenceService2{SequenceDao2 dao;@Transactional(propagation=Propagation.REQUIRED)//乐观锁时必须使用public synchronized void increment(String sequenceName){int value = dao.getValueForUpdate(sequenceName);//读取是就要加锁(selec .... for update)dao.compareAndSet(sequenceName, value+1);}}}
11.CopyOnWriteArrayList 提高效率
* 锁总结:
* (1)使用支持CAS的数据结构,避免使用锁,如Atomic...、ConcurrentMap、CopyOnWriteList、ConcurrentLinkedQueue
*(2)一定使用锁时,注意获得锁的顺序,相反顺序获得锁,易死锁
*(3)死锁无法完全避免,鸵鸟策略被很多基础框架使用
*(4)通过Dump线程的StackTrace,例如linux下执行命令kill -3 <pid>,或者Jstack -l <pid>,
* 或者使用Jconsole连接上去查看线程的StackTrace,用来诊断线程死锁的问题。
*(5)外部锁常被忽视造成死锁,比如数据库的锁
public class BriefSumUp {class Engine1{private List<Listener> listeners = new ArrayList<Listener>();public boolean addListener(Listener listener){synchronized (listeners) {return listeners.add(listener);}}public void doXXX(){synchronized (listeners) {for (Listener listener:listeners) {listener.handle();}}}}class Engine2{private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();public boolean addListener(Listener listener){return listeners.add(listener);}public void doXXX(){for (Listener listener:listeners) {listener.handle();}}}}
12.并发流程控制-CountDownLatch
public class Control {public static void main(String[] args) throws InterruptedException{new Control().Practice2();}public void Practice1() throws InterruptedException{final int COUNT =10;final CountDownLatch completeLacth = new CountDownLatch(COUNT);for(int i=0;i<COUNT;i++){Thread thread = new Thread("thread"+i){public void run(){//doxxx();try {Thread.sleep(1000);//???只有主线程才会休眠,仅一次,原因?解释: sleep是使当前线程休眠xx时间,所有线程单独休眠效果等于只有一次休眠} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName());completeLacth.countDown();//当你启动一个线程需要等待它执行结束,CountDownLatch是个很好的选择}};thread.start();}System.out.println("......");completeLacth.await();//会等到completeLacth所有线程执行结束才会执行后面的System.out.println("...end...");}public void Practice2(){final CountDownLatch startLacth = new CountDownLatch(1);for(int i=0;i<10;i++){Thread thread = new Thread("thread"+i){public void run(){try{startLacth.await();//当你启动了很多线程,你需要这些线程等到通知后才真正开始,CountDownLatch是个很好的选择}catch (InterruptedException e) {return;}System.out.println(Thread.currentThread().getName());//doxxx();}};thread.start();}//doxxx();System.out.println("...start...");startLacth.countDown();System.out.println("......");} }
13.Barrier模型
* 并发流程控制-CycliBarrier
public class Barrier {public static void main(String[] args){PerformaceTest test= new Barrier().new PerformaceTest(2);}class PerformaceTest{private int threadCount;private CyclicBarrier barrier;private int loopCount=3;public PerformaceTest(int threadCount){this.threadCount=threadCount;this.barrier= new CyclicBarrier(threadCount,new Runnable() {public void run() {collectTestResult();}});for (int i = 0; i < threadCount; i++) {Thread thread = new Thread("thread"+i){public void run(){for (int j = 0; j < loopCount; j++) {doTest();try {barrier.await();//使用Barrier来实现并发性能测试的聚合点} catch (InterruptedException e) {return;} catch (BrokenBarrierException e) {return;}}}};thread.start();}}private void doTest(){System.out.println("doTest()");};private void collectTestResult(){System.out.println("collectTestResult()");};}}
14.使用定时器
* ScheduledExecutorService:在ExecutorService的基础上,ScheduledExecutorService提供了按时间安排执行任务的功能
*schedule():安排所提交的Callable或Runnable任务在initDelay指定的时间后执行
*scheduleAtFlxedRate():安排所提交的Runnable任务按指定的间隔重复执行
*scheduleWithFlxedDelay():安排所提交的Runnable任务在每次执行完后,等待delay所指定的时间后重复执行。
*
*java.util.concurrent.Executors是ScheduledExecutorService的工厂类
*jdk以后就有ScheduledExecutorService,不要使用java.util.Timer,功能性能不如ScheduledExecutorService
public class Scheduled {public static void main(String[] args) throws InterruptedException, ExecutionException{new Scheduled().practice();}public void practice() throws InterruptedException, ExecutionException{ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);//对象的线程池大小ScheduledFuture<Object> future = scheduler.schedule(new Callable<Object>() {public Object call() throws Exception {Object result = "测试Future";//System.out.println("测试Future....");return result;}}, 1, TimeUnit.SECONDS);System.out.println(future.get());;//future.cancel(true);取消任务//scheduler.shutdown();关闭服务}}
15.大规模定时器TimerWheel
* 算法TimerWheel,适用于大规模的定时器实现。最早被用来设计实现BSD内核定时器,后被移植于ACE等框架,堪称BSD经典算法之一。
* 对定时器的各类常见操作提供接近常数时间的响应,且可根据需要很容易的扩展。
*
* 思想:把一堆任务放入一个队列里面,然后设置一个定时器每隔一定的时间产生一个随机数,然后根据这个随机数从这个队列里面取出任务,
* 然后执行。这个随机数为队列长度以内的数。
* 简单实现:
* 初始化一个定长的队列queue,每添加一个定时器任务就hash放到queue中的特定位置,如果hash时多个定时任务放到queue中的同一个index时,
* 就以桶的方式存放这些定时任务,与hashMap类似。TimerWheel中由一个定时线程不断扫描这些定时任务,
* 如果任务执行时间到把改任务交给线程池去执行,并从队列中移除,如此不断轮询。
*
* 16.并发的三大定律
* (1)Amdahl定律:gene Amdahl发现在计算机体系结构设计中,某个部件的优化对整个架构的优化和改善是有上限的。
* (2)Gustafson定律:Gustafson假设随着处理器个数的增加,计算机并行和串行的计算总量也是可以增加的。
* Gustafson定律认为加速系数几个跟处理器个数成正比。如果现实符合Gustafson假设,软件的性能也会随着处理器个数的增加而提升。
* (3)Sun-Ni定律:充分利用存储空间等计算资源,尽量的增大问题规模以得到更好/准确的解。
- 【整理】Java并发程序设计
- 《实战java高并发程序设计》源码整理及读书笔记
- java高并发程序设计
- java高并发程序设计
- java高并发程序设计
- Java并发程序设计(1)
- Java并发程序设计教程
- Java并发程序设计
- Java高并发程序设计
- Java并发程序设计-注解
- JAVA高并发程序设计
- Java高并发程序设计
- Java 并发整理笔记
- Java高并发程序设计入门
- Java高并发程序设计总结
- java 高并发程序设计-附录
- Java高并发程序设计笔记
- Java高并发程序设计读书笔记
- SDUTOJ 2543 整除(容斥原理)
- Zoj 1025 Wooden Sticks
- sql面试题
- CEGUI::String类分析
- 用19种编程语言写Hello World
- 【整理】Java并发程序设计
- Linux系统 nfs 共享及 挂载mount 配置
- HDU1013-简单的数论
- hdu4190
- 【HTTPClient 系列】HttpClient4.2.5上传文件,无中文文件名问题
- SEO有效的手段不仅仅是外链
- ibaits工具类
- Android 启动过程详解
- linux daemon