【整理】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定律:充分利用存储空间等计算资源,尽量的增大问题规模以得到更好/准确的解。


原创粉丝点击