并发API总结

来源:互联网 发布:蜂窝移动数据开关无效 编辑:程序博客网 时间:2024/06/06 11:01
通过学习《Thinking in Java》,总结并发API如下:

12.1 Thread.yield():说明自己用的cpu时间差不多了,可以让别的线程使用cpu了,不一定会被采纳,就是说别的线程不一定就会马上获得cpu
12.2 线程池有固定大小,不固定大小的(newCachedThreadPool建议使用这个),以及单线程(newSingleThreadExecutor即只能一个线程结束后,第二个线程才执行)的。shutdown():不接受新任务
12.3 后台线程daemon:t.setDaemon(true) 需在t.start()之前设定,其创建的所有线程都为后台线程。当非后台线程都停止时,后台线程会立刻终止,finally子句不会执行;
12.4 Runnable任务:class可以implements Runnable()。之后其class可以用线程池调度:
    ExecutorService exec = Executors.newCachedThreadPool();
     exec.execute(new class());
    也可以用Thread t = new Thread(new classA());
12.5 join()方法:可以理解为等待其他线程结束再开始执行自己,如在t1线程中调用t2.join(),则t1要等待完t2结束才能往下执行
12.6 异常:Interupted异常能被自己捕获,但调用isInterrupted()方法时为false
        run本身不能捕获运行时异常,需用UncaughtExceptionHandler捕获,例子如下:
        package JavaBase2;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class ExceptionThread {
    public static void main(String[] a){
        //ExecutorService exe = Executors.newCachedThreadPool(new HandlerThreadFactory());
        //ExecutorService exe = Executors.newCachedThreadPool();
        //System.out.println(new ExceptionThread());
        ExecutorService exe = MySys.getExe();
        exe.execute(new ExceptionThread2());
    }


}

class ExceptionThread2 implements Runnable{

    public void run(){
        Thread t = Thread.currentThread();
        System.out.println("run by thread " + t.getName());
        System.out.println("eh=" + t.getUncaughtExceptionHandler());
        //throw new RuntimeException();
        MySys.callExceptionMethod();
    }
}

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{

    public void uncaughtException(Thread t,Throwable e){
        System.out.println("caught " + e);
        ExecutorService exe = MySys.getExe();
        exe.execute(new NormalThread());
        exe.execute(new NormalThread());

    }
}

class HandlerThreadFactory implements ThreadFactory{

    public Thread newThread(Runnable r){
        System.out.println(this + " create new Thread");
        Thread t = new Thread(r);
        System.out.println("created " + t);
        t.setUncaughtExceptionHandler(MySys.getEh());
        System.out.println("eh=" + t.getUncaughtExceptionHandler());
        return t;

    }

}

class NormalThread implements Runnable{
    public void run(){
        Thread t = Thread.currentThread();
        System.out.println("new a normal thread=" + t.getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("sleep end....");
    }
}

class MySys{
    //private static ExecutorService exe = Executors.newSingleThreadExecutor(new HandlerThreadFactory());
    private static ExecutorService exe = Executors.newCachedThreadPool(new HandlerThreadFactory());
    private static MyUncaughtExceptionHandler eh = new MyUncaughtExceptionHandler();
    public static ExecutorService getExe(){
        return exe;
    }
    public static MyUncaughtExceptionHandler getEh(){
        return eh;
    }    

    public static void callExceptionMethod(){
        System.out.println("Exception method run.....");
        throw new RuntimeException();
    }
}


12.7 volatile的使用:保证工作线程从jvm内存拿到的值是最新的;也就是确保有可视性,即主内存的值修改后,马上对全部工作线程可见,全部工作线程内存的值再次使用时会到主内存读取。java的64位操作可能有字撕裂。但不是线程安全的,详见:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html
12.8 synchronized:锁住共享资源,其一般表现为对象锁,即锁住对象形式存在的内存片段。一个对象一把锁,多个synchronized共用一把锁,一个对象的多个synchronized是互斥的。对于读和写的共享资源都要加锁
        一个任务可以获得对象的多个锁,即调用多个synchronized片段,采用计数器计数,当为0时说明调用完成。
        类也可以有synchronized,synchronized static
        同步块比同步方法性能更优
        同步块须给定一个对象上锁,一般是this,锁住当前对象,当前对象的其他临界资源也被锁住
        如果在一个对象上有两个同步锁,其加锁的对象一个是当期对象,一个是其他对象,则这两个同步锁不会互斥
        
12.9 显式锁:进出的时候加锁解锁,解锁在return之后:
        private int count = 0;
        private Lock lock=new ReentrantLock();
        public int next(){
            try{
               lock.lock();
                ++count;
                Thread.yield();    
                ++count;
                return count;
            }finally{
                lock.unlock();
             }
 12.10 原子性:应用于除long和double之外的所有基本类型之上的“简单操作”,也就是赋值和返回值。            
 12.11 中断:I/O和synchronized是不可中断的,除非中断其依赖的底层资源,sleep可以直接用ExectorServicce.submit().cancel(true)中断;
12.12  在构造器中锁了自己,其他任务通过自身的引用也会互斥:
 
12.13 ExectorService exec = Executors.newCachedThreadPool();
            exec.shutdownNow();//调用所有由他控制的线程的interrupt();
12.14 wait():是Object的方法,释放锁,相当于挂起(而sleep不会释放锁),可以用notify()和notifyAll()   唤醒,也可以等时间到期唤醒。只能在同步块中使用,否则会报运行异常,因为使用者需获得锁。
 12.15 notify():唤醒等待锁的某个任务,notifyAll()唤醒等待锁的全部任务,而且只是唤醒等待同一个对象锁的全部任务,等待不同对象锁的任务不会唤醒;
12.16 List<L> data = Collections.synchronizedList(new ArrayList<L>): data的所有方法都是线程安全的。
12.17 Semaphore:控制多个任务访问共享资源
12.18 ExecutorService exec = Executors.newCachedThreadPool();
          线程的run方法的while用:
public void run(){ 
try{
         while(!Thread.interrupted()){}
  }catch{  }

当调用exec.shutdownNow()时,可以终止while循环

12.20 CoutDownLatch:一种用来等待一组任务完成,其他任务才能执行的锁
        CountDownLatch latch = new CountDownLatch(100);
    如果A调用了latch.await();
    B1调用了latch.countDown();
    B2调用了latch.countDown();
    ........................B100调用了latch.countDown();即减到了0;A任务才能往下走

12.21 CyclicBarrier:与CountDownLatch类似,不同的是其可以循环计数。
12.22 AtomicLong,Lock,synchronized比较:优先使用syn锁,因为可读性好;计数器用Atomic。
12.23 免锁容器CopyOnwriteArrayList:读写可同时进行,修改时有副本,当修改完成时一个原子性操作修改原来的容器,不会抛出ConcurrentModificationException。
12.24 读写锁ReadWriteLock,读要等写完才能读,多个读不互斥。当写锁被其他任务持有时,任何读取者都不能访问,直到写锁释放为止。
12.25 乐观锁,atomic.compareAndSet(oldvalue,newvalue),更新时如新值不等于旧值会失败。
12.26 延迟队列DelayQueue,延迟到期才能从队列取走。延迟最多最后执行,用CompareTo方法比较顺序。Comparable可以使用范型。
12.17 优先队列PriorityBlockingQueue,也是基于Comparable,排在前面的优先级最高先执行,与延迟相反。
0 0