java 并发工具的使用

并发工具的使用

Thread 和Runnable 创建新的线程

synchronized 实现同步

wait 和 notify 支持线程通讯

应对多核系统的Fork/Join框架

并发API包

java.util.concurrent

同步器

同步线程间高级的通信方法

Semaphore

  1. 实现了经典信号量

  2. 信号量通过计数器控制对共享信号量的访问

  3. 如果计数器大于0允许访问,等于0拒绝访问

  4. 计数器是允许访问共享资源的许可证

构造器

Semaphore(int num)

设置可以共享资源的线程的数量

Semaphore(int num,boolean how)

how: true是否按照等待顺序获取许可证

获取许可证

void acquire()

void acquire(int num)

释放许可证

void release()

void release(int num)

为了控制信号量对资源的访问必须先用acquire进行访问访问,使用完后通过release释放

class Shared {
    public static int count = 0;
}
class IncThread implements Runnable {
    Semaphore sema;
    String name;

    public IncThread(Semaphore sema, String name) {
        this.sema = sema;
        this.name = name;
        new Thread(this).start();
    }

    @Override
    public void run() {
        System.out.println(name + "\twait to get Semaphore");

        try {
            sema.acquire();
            
            System.out.println(name +"\t alread has Semaphore");
        
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        for(int  i=0;i<5;i++) {
            Shared.count++;
            System.out.println(name + "\tShared.count=\t" + Shared.count);
            
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        sema.release();

        System.out.println(name + "\t over");
        
    }
}
class DecThread implements Runnable{
    Semaphore sema;
    String name;
    public DecThread(Semaphore sema,String name) {
        this.sema = sema;
        this.name = name;
        new Thread(this).start();
    }

    @Override
    public void run() {
        System.out.println(name + "\t wait get Semaphore");
        try {
            sema.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "\t has get Semaphore");
        
        for(int i=0;i<5;i++) {
            Shared.count--;
            System.out.println(name + "\tShared.count=" + Shared.count);
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        sema.release();
        System.out.println(name + "\t over");
    }
    
}
    public static void main(String[] args) {
        Semaphore sema = new Semaphore(1);
        new IncThread(sema, "A");
        new DecThread(sema, "B");
    }
A	wait to get Semaphore
A	 alread has Semaphore
A	Shared.count=	1
B	 wait get Semaphore
A	Shared.count=	2
A	Shared.count=	3
A	Shared.count=	4
A	Shared.count=	5
B	 has get Semaphore
B	Shared.count=4
A	 over
B	Shared.count=3
B	Shared.count=2
B	Shared.count=1
B	Shared.count=0
B	 over

当Semaphore(0) 的时候是没有线程可以获得许可证的,这个时候所有线程都会进入阻塞,可以保证其他线程先进性执行

使用生产者和消费者进行演示

class Q {
   
    private static Semaphore semaCon = new Semaphore(0);

    private static Semaphore semaPro = new Semaphore(1);
    
    int item;
    
    public int  get() {
        
        try {
            semaCon.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //System.out.println(item);
        semaPro.release();
        return item;
    }
    
    public void put(int item) {
        try {
            semaPro.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.item = item;
        semaCon.release();
    }
}
class Producer implements Runnable{
    
    Q q;
    public Producer(Q q,String name) {
        this.q = q;
        new Thread(this,"producer-" + name).start();;
    }

    @Override
    public void run() {

        for(int i=0;i<10;i++) {
            q.put(i*100);
            System.out.println(Thread.currentThread().getName()+"\t" + i*100);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
}
class Consumer implements Runnable{
    
    Q q;
    public Consumer(Q q,String name) {
        this.q = q;
        new Thread(this,"consumer-" + name).start();;
    }

    @Override
    public void run() {

        for(int i=0;i<10;i++) {
            System.out.println(Thread.currentThread().getName()+"\t" + q.get());
           // q.get();
        }
    }
    
}
producer-张三	0
consumer-李四	0
consumer-李四	100
producer-张三	100
consumer-王五	200
producer-张三	200
consumer-李四	300
producer-张三	300
producer-张三	400
consumer-王五	400
producer-张三	500
consumer-李四	500
consumer-王五	600
producer-张三	600
producer-张三	700
consumer-李四	700
producer-张三	800
consumer-王五	800
consumer-李四	900
producer-张三	900

CountDownLatch

希望线程进行等待,直到发生一个或者多个事件为止

CountDownLatch(int num) 在释放锁需要发生的事件

class MyThread implements Runnable{
    
    CountDownLatch cdl;
    
    public MyThread(CountDownLatch cdl) {
        this.cdl = cdl;
        new Thread(this).start();
    } 
        
    

    @Override
    public void run() {
        
        for(int i=0;i<5;i++) {
            cdl.countDown();
            System.out.println(i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    }}
  public static void main(String[] args) {
        CountDownLatch cdl = new CountDownLatch(5);
        
        new MyThread(cdl);
        //必须先执行
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("done");
    }
0
1
2
3
4
done

CyclicBarrier

  1. 两个或者多个线程必须在指定的时间点进行等待,直到达到指定数量的线程数

  2. CyclicBarrie 可以重复利用

  3. 流线化的解决问题

代码演示

class MyThread1 implements Runnable{
    CyclicBarrier cb ;
    String name;
    public MyThread1(CyclicBarrier cb,String name) {
        this.cb = cb;
        this.name = name;
        new Thread(this,name).start();
    }

    @Override
    public void run() {
        System.out.println(name);
        try {
            cb.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        
    }
    
}
class BarrerRun implements Runnable{
    

    @Override
    public void run() {
        System.out.println("BarrerRun");
        
    }
    
}
   public static void main(String[] args) {
        CyclicBarrier cb = new CyclicBarrier(3,new BarrerRun());
        System.out.println("start...");
        for(char i = 'A';i<='Z';i++) {
            new MyThread1(cb, String.valueOf(i));
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
       
    }
start...
A
B
C
BarrerRun
D
E
F
BarrerRun
G
H
I
BarrerRun
J
K
L
BarrerRun
M
N
O
BarrerRun
P
Q
R
BarrerRun
S
T
U
BarrerRun
V
W
X
BarrerRun
Y
Z

Exchanger

  1. 设计目的简化两个线程之间的数据交换

Exchanger 泛型类 T 需要交换的数据类型

V exchange(V v) 交换数据方法

一个线程拿到数据后其他线程无法拿到数据


class T1 implements Runnable {
    String name;
    Exchanger<String> exe;
    char c = 'A';

    public T1(Exchanger<String> exe, String name) {
        this.exe = exe;
        this.name = name;
        new Thread(this,name).start();
    }

    @Override
    public void run() {

        for (int i = 0; i < 3; i++) {
            String str = "";
            for (int j = 0; j < 5; j++) {
                str += c++;
            }

            try {
                exe.exchange(str);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }

}

class T2 implements Runnable {
    
    String name;
    Exchanger<String> exe;
    
    public T2(Exchanger<String> exe,String name) {
        this.name = name;
        this.exe = exe;
        new Thread(this,name).start();
    }
    
    @Override
    public void run() {
        for(int i=0;i<3;i++) {
            
            try {
                String ret = exe.exchange(new String());
                System.out.println(Thread.currentThread().getName() + "\t" + ret);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            
        }
    }

}


        Exchanger<String> exe = new Exchanger<String>();
        
        new T1(exe,"T1");
        new T2(exe,"T2");
        /**
         *一个线程拿到数据后其他线程拿不到数据
         */
        new T2(exe,"T3");
        new T2(exe,"T4");
    }

T2	ABCDE
T3	
T3	KLMNO
T4	
T3	
T2	FGHIJ
T4	
T4	
T2	

Phaser

  1. 允许标识一个或者多个线程进行同步
  2. 同步一个阶段的工作,然后进行下一阶段的工作,当只有一个阶段的时候,功能与CyclicBarrier功能类似
  3. 主要用途是同步多个阶段额内容

使用方式

  1. 先创建Phaser实例
  2. 再注册一个或者多个party,使用register()方法在构造器中指定 party的数量
  3. 对于注册的party,Phaser会进行等待
  4. 直到注册的所有party完成为止
  5. party通过调用Phaser的方法进通知,arrive等方法
  6. 所有party完成后这一阶段完成,然后推进到下一阶段
class ThreadPhaser implements Runnable{
    
    Phaser p;
    String name;
    public ThreadPhaser(Phaser p,String name) {
        this.p = p;
        this.name = name;
        p.register();
        new Thread(this,name).start();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " beginning phaser one");
        
        //等待其他线程完成工作
        p.arriveAndAwaitAdvance();
        
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println(Thread.currentThread().getName() + " beginning phaser two");
        p.arriveAndAwaitAdvance();
        
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        
        
        System.out.println(Thread.currentThread().getName() + " beginning phaser three");
      
        //完成工作后销毁自身
        p.arriveAndDeregister();
        
        
    }
    
}
    public static void main(String[] args) {
          
        Phaser phaser = new Phaser(1);
        int count;
        System.out.println("....start....");
        
        new ThreadPhaser(phaser,"A");
        new ThreadPhaser(phaser,"B");
        new ThreadPhaser(phaser,"C");
        
        count = phaser.getPhase();
        //通知主线程进行等待
        phaser.arriveAndAwaitAdvance();
        System.out.println("当前执行:" + count + " complete");
        
        count = phaser.getPhase();
        phaser.arriveAndAwaitAdvance();
        System.out.println("当前执行:" + count + " complete");
        
        count = phaser.getPhase();
        phaser.arriveAndAwaitAdvance();
        System.out.println("当前执行:" + count + " complete");

        //销毁三个线程
        phaser.arriveAndDeregister();
        
        if(phaser.isTerminated()) {
            System.out.println("this the phaser is terminated");
        }
        
        System.out.println("........over..........");
    
    }
....start....
B beginning phaser one
C beginning phaser one
A beginning phaser one
当前执行:0 complete
C beginning phaser two
B beginning phaser two
A beginning phaser two
当前执行:1 complete
A beginning phaser three
B beginning phaser three
C beginning phaser three
当前执行:2 complete
this the phaser is terminated
........over..........

精确地把控发生的操作

重写onAdvance

public class MyPhaser extends Phaser{

    int numPhaser;
    
    public MyPhaser(int parties,int phaserCount) {
        super(parties);
        this.numPhaser = phaserCount - 1;
    }
    
    @Override
    protected boolean onAdvance(int p, int registeredParties) {
        
        System.out.println("Phaser " + p + " complete");
        
        if(p == numPhaser || registeredParties == 0) {
            return true;
        }
        return false;
    }
}
class MyThreadPhaser implements Runnable{
    
    MyPhaser m;
    String name;
    public MyThreadPhaser(MyPhaser m,String name) {
        this.m = m;
        this.name = name;
        m.register();
        new Thread(this,name).start();
        }

    @Override
    public void run() {
        
        while(!m.isTerminated()) {
            System.out.println(Thread.currentThread().getName() + "\tbeging " + m.getPhase() );
            m.arriveAndAwaitAdvance();
            
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
}
   public static void main(String[] args) {
        MyPhaser mp = new MyPhaser(1, 4);
        
        new MyThreadPhaser(mp,"A");
        new MyThreadPhaser(mp,"B");
        new MyThreadPhaser(mp,"C");
        
        while(!mp.isTerminated()) {
            mp.arriveAndAwaitAdvance();
        }
        
        if(mp.isTerminated()) {
            System.out.println("over");
        }
    }

A	beging 0
B	beging 0
C	beging 0
Phaser 0 complete
A	beging 1
B	beging 1
C	beging 1
Phaser 1 complete
B	beging 2
A	beging 2
C	beging 2
Phaser 2 complete
C	beging 3
A	beging 3
B	beging 3
Phaser 3 complete
over

执行器

  1. 执行器管理线程的执行
  2. 启动和控制线程的执行
  3. 执行器为Thread类管理线程提供了一种替代方案
  4. 核心接口 Executor
  5. ExecutorService管理控制线程执行的方法 shutdown()用于停止调用ExecutorService对象
  6. ScheduledExecutorService接口定义了线程调度
  7. ThreadPoolExecutor 支持线程池
  8. ScheduledThredPoolExecutor 支持线程池和线程调度
  9. ForkJoinPool 后面再说
Executor接口
ExecutorService接口
ScheduledExecutorService接口
AbstractExecutorService抽象类
ForkJoinPool实现类
ThreadPoolExecutor实现类
ScheduledThreadPoolExecutor实现类

一个执行器示例:

ExecutorService exe = Executors.newFixedThreadPool(2);

exe.shutdown(); 最后一定要关掉线程池,不然程序不会结束

class MyThreadExe implements Runnable {

    String name;
    CountDownLatch cdl;

    public MyThreadExe(CountDownLatch cdl, String name) {
        this.cdl = cdl;
        this.name = name;
    }

    @Override
    public void run() {

        for (int i = 0; i < 5; i++) {
            System.out.println(name + " : " + i);
            cdl.countDown();

        }

    }
}
  public static void main(String[] args) {

        CountDownLatch cdl1 = new CountDownLatch(5);
        CountDownLatch cdl2 = new CountDownLatch(5);
        CountDownLatch cdl3 = new CountDownLatch(5);
        CountDownLatch cdl4 = new CountDownLatch(5);
        
        System.out.println("....start....");
        
        ExecutorService exe = Executors.newFixedThreadPool(2);
        exe.execute(new MyThreadExe(cdl2, "A"));
        exe.execute(new MyThreadExe(cdl2, "B"));
        exe.execute(new MyThreadExe(cdl3, "C"));
        exe.execute(new MyThreadExe(cdl4, "D"));
        try {
            cdl1.await();
            cdl2.await();
            cdl3.await();
            cdl4.await();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        exe.shutdown();
    }
....start....
A : 0
A : 1
A : 2
A : 3
A : 4
C : 0
C : 1
C : 2
C : 3
C : 4
D : 0
D : 1
D : 2
D : 3
D : 4
B : 0
B : 1
B : 2
B : 3
B : 4
done

Callable

  1. Callable 表示返回值的线程,应用程序可以用Callable计算结果,然后将结果返回给调用线程

interface Callable

V call() throws Exception call希望执行的任务

  1. Callable 任务 通过ExecutorService 调用 submit() 方法

Future submit(Runnable task, T result);

interface Future

Future 通过get 方法返回

V get() 无限期的等待 V get(long timeout, TimeUnit unit)在指定的时间内等待

  1. Runnable 没有返回值 Callable依赖于 ExecutorService 的submit
 public static void main(String[] args) {
        
        ExecutorService exe = Executors.newFixedThreadPool(3);
        Future<Integer> f1;
        Future<Double> f2;
        Future<Integer> f3;
        
        System.out.println(".....start.....");
        
        f1 = exe.submit(new Sum(100));
        f2 = exe.submit(new Hypo(3, 4));
        f3 = exe.submit(new Factorial(10));
            
        try {
            //从上向下等待依次执行
            System.out.println(f1.get());
            System.out.println(f2.get());
            System.out.println(f3.get());
           
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        
        exe.shutdown();
        System.out.println("done");
        
    }
class Sum implements Callable<Integer>{
    
    int stop;
    
    public Sum(int stop) {
        this.stop = stop;
    }

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i=1;i<=stop;i++) {
            sum += i;
        }
        
        Thread.sleep(2000);
        
        return sum;
    }
}
class Hypo implements Callable<Double>{
    
    double a;
    double b;
    
    public Hypo(double a,double b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public Double call() throws Exception {
        Thread.sleep(4000);
       return Math.sqrt((a*a) + (b*b));
    }
    
}
class Factorial implements Callable<Integer>{

    int stop;
    
    public Factorial(int stop) {
        this.stop = stop;
    }
    @Override
    public Integer call() {
        int ret = 1;
        for(int i=1;i<=stop;i++) {
            ret *= i;
        }
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ret;
    }
    
}
.....start.....
5050
5.0
3628800
done

TimeUnit

  1. 并发api 中超时时间单位
  2. 指定时间单位粒度
  3. 无法保证系统能否达到TimeUnit定义的粒度
    @Test
    public void test1() {
        TimeUnit t = TimeUnit.DAYS;
        System.out.println(t.toDays(1));//天
        System.out.println(t.toHours(1));//小时
        System.out.println(t.toMicros(1));//微秒
        System.out.println(t.toMillis(1));//毫秒
        System.out.println(t.toMinutes(1));//分钟
        System.out.println(t.toNanos(1));//纳秒
        System.out.println(t.toSeconds(1));//秒
    }
    
    @Test
    public void test2() {
        TimeUnit t = TimeUnit.HOURS;
        System.out.println(t.toDays(1));//天
        System.out.println(t.toHours(1));//小时
        System.out.println(t.toMicros(1));//微秒
        System.out.println(t.toMillis(1));//毫秒
        System.out.println(t.toMinutes(1));//分钟
        System.out.println(t.toNanos(1));//纳秒
        System.out.println(t.toSeconds(1));//秒
    }
    
    @Test
    public void test3() {
        TimeUnit t = TimeUnit.MINUTES;
        System.out.println(t.toDays(1));//天
        System.out.println(t.toHours(1));//小时
        System.out.println(t.toMicros(1));//微秒
        System.out.println(t.toMillis(1));//毫秒
        System.out.println(t.toMinutes(1));//分钟
        System.out.println(t.toNanos(1));//纳秒
        System.out.println(t.toSeconds(1));//秒
    }
    
    @Test
    public void test4() {
        TimeUnit t = TimeUnit.MICROSECONDS;
        System.out.println(t.toDays(1));//天
        System.out.println(t.toHours(1));//小时
        System.out.println(t.toMicros(1));//微秒
        System.out.println(t.toMillis(1));//毫秒
        System.out.println(t.toMinutes(1));//分钟
        System.out.println(t.toNanos(1));//纳秒
        System.out.println(t.toSeconds(1));//秒
    }
    
    @Test
    public void test5() {
        TimeUnit t = TimeUnit.MILLISECONDS;
        System.out.println(t.toDays(1));//天
        System.out.println(t.toHours(1));//小时
        System.out.println(t.toMicros(1));//微秒
        System.out.println(t.toMillis(1));//毫秒
        System.out.println(t.toMinutes(1));//分钟
        System.out.println(t.toNanos(1));//纳秒
        System.out.println(t.toSeconds(1));//秒
    }

并发集合

暂不介绍

  1. 多个线程共享数据时,保护数据
  2. 所有锁都实现了Lock接口
  3. 申请锁调用lock()方法,如果得不到,lock()方法会等待
  4. 释放锁会调用unlock()
  5. trylock()看看锁是否可得

ReentrantLock 可重入锁

  1. 当前持有锁的线程可重复进入锁,当然必须有相同数量的lock 和unlock相互进行抵消。否则试图申请锁的线程会被挂起,知道锁不再使用

    代码示例

       public static void main(String[] args) {
            ReentrantLock lock = new ReentrantLock();
            new LockThread(lock, "A");
            new LockThread(lock, "B");
            new LockThread(lock, "C");
            new LockThread(lock, "D");
        }
    
    class Shared{
        
        public static int count = 0;
    }
    
    class LockThread implements Runnable{
        
        private String name;
        ReentrantLock lock;
        public LockThread(ReentrantLock lock, String name) {
            this.name = name;
            this.lock = lock;
            new Thread(this,name).start();
        }
    
        @Override
        public void run() {
            System.out.println("start----" + name);
            
          
            try {
                System.out.println( name + "---is waiting to lock...");
                lock.lock();
                System.out.println(name + "----- lock count");
                Shared.count++;
                System.out.println(name + ":" + Shared.count);
                System.out.println(name + "sleep");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                System.out.println(name + " is unlocking count");
                lock.unlock();
            }
            
            
        }
        
    }
    
    start----C
    start----A
    start----D
    start----B
    D---is waiting to lock...
    A---is waiting to lock...
    C---is waiting to lock...
    D----- lock count
    B---is waiting to lock...
    D:1
    Dsleep
    D is unlocking count
    C----- lock count
    C:2
    Csleep
    C is unlocking count
    A----- lock count
    A:3
    Asleep
    A is unlocking count
    B----- lock count
    B:4
    Bsleep
    B is unlocking count
    
    

    原子操作

    1. 不需要锁和其他同步操作,使操作不可中断
    2. 原子操作通过一些类和方法进行完成例如:AtomicInteger,当然还有AtomicDouble等
    
        public static void main(String[] args) {
            new AtomicThread("A");
            new AtomicThread("B");
            new AtomicThread("C");
        }
    
    class Shared {
        public static AtomicInteger count = new AtomicInteger(0);
    }
    
    class AtomicThread implements Runnable{
    
        private String name;
    
        public AtomicThread(String name) {
            this.name = name;
            new Thread(this,name).start();
        }
        
        @Override
        public void run() {
            System.out.println(name + " start ... ");
            for(int i=0;i<3;i++) {
                System.out.println(name + " got " + i + " " + Shared.count.getAndSet(i));
            }
            System.out.println("======================================================");
            
        }
        
    }
    
    B start ... 
    B got 0 0
    B got 1 0
    B got 2 1
    ======================================================
    A start ... 
    A got 0 2
    A got 1 0
    A got 2 1
    ======================================================
    C start ... 
    C got 0 2
    C got 1 0
    C got 2 1
    ======================================================
    
    

Fork/Join框架

  1. 并行变成
  2. java7提供的支持并行编程的类和接口被称为Fork/Join框架
  3. 简化了线程的创建和使用
  4. 自动使用多处理器,自动的伸缩
  5. 分而治之的策略,递归将任务分成更小的子任务,直到子任务足够小并且合理

ForkJoinTask< V > 定义任务抽象类

  1. 与Thread 表示任务的轻量级抽象,而不是执行线程
  2. 通过ForkJoinPool类型的线程池进行管理执行
  3. 核心方法 fork() join()
  4. fork 调用任务的异步执行提交,也就是说fork方法的线程将持续运行
  5. join方法等待调用该方法的任务终止
  6. fork join方法可以开始一个或者多个新任务,然后等待他们结束
  7. invoke 将fork和join方法连接在一起,开始一个任务并等待该任务结束
  8. invoke 当任务结束才会继续执行
  9. invokeAll可以同时调用多个任务
  10. 调用线程会等待所有指定的任务结束

ForkJoinPool 管理ForkJoinTask的执行

  1. 创建好任务就会开始执行任务,第一个任务通常被认为是主任务
  2. 使用守护线程,当所有任务线程都终止后,守护线程自动终止
  3. 所以不需要显示的关闭

RecusiveAction ForkJoinTask 的子类用于不返回值的任务

RecusiveTask< V > ForkJoinTask< V > 的子类用于返回值的任务

class RecursiveActionChils extends RecursiveAction{
    
    private static final long serialVersionUID = 1L;
    
    private final  static Integer limit  = 1000;
    private int start;
    private int end;
    private double[] arrs;
    
    public RecursiveActionChils(double[] arrs,int start,int end) {
        this.start = start;
        this.end = end;
        this.arrs = arrs;
    }

    @Override
    protected void compute() {
      if(end - start < limit) {
          for(int i=start;i<end;i++) {
              arrs[i] = Math.sqrt(arrs[i]);
          }
      }else {
          int middle = (end+start)/2;
          
          invokeAll(new RecursiveActionChils(arrs, start, middle),new RecursiveActionChils(arrs, middle, end));
      }
    }
}

 public static void main(String[] args) {
        //java8以前需要显示的创建ForkJoinPool
        //ForkJoinPool pool = new ForkJoinPool();
        //java8以后可以从公共池中获取一个ForkJoinPool
      //也可以不需要声明ForkJoinPool 如果任务不在公共池中可以直接task.invoke()方法,使任务自动在公共池中执行
       // ForkJoinPool pool = ForkJoinPool.commonPool();
        double[] arrs = new double[10000];
        
        for(int i=0;i<arrs.length;i++) {
            arrs[i] = i;
        }
        
        for(int i=1000;i<1010;i++) {
            System.out.printf("%f \t",arrs[i]);
        }
        System.out.println();
        RecursiveActionChils task = new RecursiveActionChils(arrs, 0, arrs.length);
        //pool.invoke(task);
        task.invoke();
        
        for(int i=1000;i<1010;i++) {
            System.out.printf("%f \t",arrs[i]);
        }
    }

可以从下面看出数据被分割成很多份进行递归计算

1000.000000 	1001.000000 	1002.000000 	1003.000000 	1004.000000 	1005.000000 	1006.000000 	1007.000000 	1008.000000 	1009.000000 	
开始 0  结束10000 
开始 0  结束5000 
开始 5000  结束10000 
开始 2500  结束5000 
开始 2500  结束3750 
开始 2500  结束3125 
开始 3125  结束3750 
开始 3750  结束5000 
开始 3750  结束4375 
开始 4375  结束5000 
开始 0  结束2500 
开始 0  结束1250 
开始 0  结束625 
开始 625  结束1250 
开始 1250  结束2500 
开始 1250  结束1875 
开始 7500  结束10000 
开始 7500  结束8750 
开始 7500  结束8125 
开始 8125  结束8750 
开始 8750  结束10000 
开始 8750  结束9375 
开始 9375  结束10000 
开始 5000  结束7500 
开始 5000  结束6250 
开始 5000  结束5625 
开始 1875  结束2500 
开始 5625  结束6250 
开始 6250  结束7500 
开始 6250  结束6875 
开始 6875  结束7500 
31.622777 	31.638584 	31.654384 	31.670175 	31.685959 	31.701735 	31.717503 	31.733263 	31.749016 	31.764760 	

并行级别

构造器指定并行级别

ForkJoinPool(int pLevel)

pLeve 大于0小于设备定义的级别

增加级别 增加会减少时间,提高程序的运行效率

class Transform extends RecursiveAction{
    
    private static final long serialVersionUID = 1L;
    
    private int limit;
    private double[] data;
    private int start,end;

    public Transform(int limit,double[] data,int start,int end) {
        this.limit = limit;
        this.data = data;
        this.start= start;
        this.end = end;
    }
    
    @Override
    protected void compute() {
        
        if(end - start > limit) {
            for(int i =start;i<end;i++) {
                if(data[i] % 2 == 0) {
                    data[i] = Math.sqrt(data[i]);
                }else{
                    data[i] = Math.cbrt(data[i]);
                }
            }
        }else {
            int middle = (end + start)/2;
            invokeAll(new Transform(limit,data,start,middle),new Transform(limit,data,middle,end));
        }
    }
    
}
public static void main(String[] args) {
        int level = Integer.valueOf(args[1]);
        int limit = Integer.valueOf(args[0]);
        
        long begin,stop;
        
        ForkJoinPool pool = new ForkJoinPool(level);
        
        double[] arrs = new double[10000];
        
        for(int i=0;i<arrs.length;i++) {
            arrs[i] = i;
        }
        
        Transform tf = new Transform(limit,arrs,0,arrs.length);
        
        begin = System.nanoTime();
        
        pool.invoke(tf);
        
        stop = System.nanoTime();
        
        System.out.printf("临界点:%d\n级别:%d\n时间:%dns\n",limit,level,(stop - begin));
        
        
    }

多次测试结果

临界点:1000
级别:1
时间:3493200ns

临界点:1000
级别:1
时间:3020473ns

临界点:1000
级别:2
时间:6627812ns

临界点:1000
级别:3
时间:3178464ns

临界点:1000
级别:4
时间:4997216ns

临界点:500
级别:4
时间:3904037ns

临界点:500
级别:1
时间:4001381ns



获取当前运行级别

pool.getParallelism()

对于创建的池,默认级别等于可用处理器的数量

 System.out.println("运行级别:" + pool.getParallelism());

获取公共池的运行级别:

 ForkJoinPool pool = ForkJoinPool.commonPool();
 //当前公共池的运行级别
 System.out.println(pool.getParallelism());//3
 //可用的处理器数量
 System.out.println(Runtime.getRuntime().availableProcessors());//4

RecursiveTask< V > 一个有返回值的示例

与上面的列子相比compute要返回结果

通过fork join 方法开启子任务

不能通过invokeAll 隐式的开启子任务


class Sum extends RecursiveTask<Double>{

    private static final long serialVersionUID = 1L;
    
    private double[] data;
    private final static int limit = 500;
    private int start,end;
    public Sum(double[] data,int start,int end) {
        this.data = data;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Double compute() {
        
        double sum = 0;
        System.out.printf("开始:%d  结束 :%d\n",start,end);
        
        if( end - start < limit) {
            for(int i=start;i<end;i++) {
                sum += data[i];
            }
        }else {
            int middle = (end + start)/2;
            
            Sum s1 = new Sum(data,start,middle);
            Sum s2 = new Sum(data,middle,end);
            
            //该任务启动不会等待任务结束
          //将每个任务的结果相加
              
            s1.fork();
            s2.fork();
            sum = s1.join() + s2.join();
            
            /*s1.fork();
            sum = s1.join() + s2.invoke();*/
            
            
            /* s1.fork();
            sum = s2.compute() + s1.join(); */
        }
        
        System.out.printf("结果:%f\n",sum);
        return sum;
    }
    
}
  public static void main(String[] args) {
        
        ForkJoinPool pool = new ForkJoinPool();
        
        double[] arrs = new double[5000];
        
        for(int i=0;i<arrs.length;i++) {
            arrs[i] = (i&1)== 0?i:-i;
        }
        
        for(int i=100;i<110;i++) {
            System.out.printf("%f\t",arrs[i]);
        }
        
        System.out.println();
        
        Sum s = new Sum(arrs,0,arrs.length);
        
        double sum = pool.invoke(s);
        
        System.out.println(sum);
        
        
    }
100.000000	-101.000000	102.000000	-103.000000	104.000000	-105.000000	106.000000	-107.000000	108.000000	-109.000000	
开始:0  结束 :5000
开始:2500  结束 :5000
开始:0  结束 :2500
开始:2500  结束 :3750
开始:2500  结束 :3125
开始:2500  结束 :2812
结果:-156.000000
开始:2812  结束 :3125
结果:2968.000000
结果:2812.000000
开始:3125  结束 :3750
开始:3125  结束 :3437
结果:156.000000
开始:3437  结束 :3750
结果:-3593.000000
结果:-3437.000000
结果:-625.000000
开始:3750  结束 :5000
开始:3750  结束 :4375
开始:3750  结束 :4062
结果:-156.000000
开始:4062  结束 :4375
结果:4218.000000
结果:4062.000000
开始:4375  结束 :5000
开始:4375  结束 :4687
结果:156.000000
开始:4687  结束 :5000
结果:-4843.000000
结果:-4687.000000
结果:-625.000000
开始:0  结束 :1250
开始:0  结束 :625
开始:0  结束 :312
开始:1250  结束 :2500
结果:-156.000000
结果:-1250.000000
开始:625  结束 :1250
开始:625  结束 :937
结果:156.000000
开始:937  结束 :1250
结果:-1093.000000
结果:-937.000000
开始:1875  结束 :2500
开始:1875  结束 :2187
结果:156.000000
开始:2187  结束 :2500
结果:-2343.000000
结果:-2187.000000
开始:312  结束 :625
结果:468.000000
结果:312.000000
结果:-625.000000
开始:1250  结束 :1875
开始:1250  结束 :1562
开始:1562  结束 :1875
结果:1718.000000
结果:-156.000000
结果:1562.000000
结果:-625.000000
结果:-1250.000000
结果:-2500.000000
-2500.0

异步执行任务

public void execute(ForkJoinTask<?> task)

ForkJoinPool类

pool.execute(task);

取消任务

public boolean cancel(boolean mayInterruptIfRunning)

ForkJoinTask

public final boolean isCancelled() 任务是否被取消

任务是否完成

任务正常完成,没有抛出异常也没有取消任务

public final boolean isCompletedNormally() 完成返回TRUE,否则false

因为取消或者抛出异常的情况下而完成的返回true,否则false

public final boolean isCompletedAbnormally()

重启任务

  1. 正常情况下任务完成后不能重新启动任务
  2. 但是可以回到任务的初始状态,从而可以重新运行

public void reinitialize()

    task.reinitialize();
        pool.invoke(task);

其他

将Runnable Callable 转换为ForkJoinTask

public static ForkJoinTask<?> adapt(Runnable runnable)
public static ForkJoinTask adapt(Callable<? extends T> callable)

class RunnTOForkJoin implements Runnable{
    private int limit = 10;
    private int start,end;
    private String name;
    private int [] data;
    public RunnTOForkJoin(String name,int start,int end,int[] data) {
        this.name = name;
        this.start = start;
        this.end = end;
        this.data = data;
       // new Thread(this,name).start();
    }

    @Override
    public void run() {
      // System.out.printf("%s 的开始:%d  结束:%d\n",name,start,end);
        if(end -start < limit) {
            for(int i=start;i<end;i++) {
                data[i] = (int)Math.sqrt(data[i]);
            }
            System.out.printf("%s 每一次最小单位的结果\n",name);
        }else {
            int middle = (end + start)/2;
            
            ForkJoinTask<?> task1 = ForkJoinTask.adapt(new RunnTOForkJoin("R",start,middle,data));
            ForkJoinTask<?> task2 = ForkJoinTask.adapt(new RunnTOForkJoin("R",middle,end,data));
            task1.invoke();
            task2.invoke();
        }
        
    }
    
}
    public static void main(String[] args) {
        
        ForkJoinPool pool = new ForkJoinPool();
        
        int[] arrs = new int[100];
        for(int i=0;i<arrs.length;i++) {
            arrs[i] = i;
        }
        for(int i=20;i<30;i++) {
            System.out.printf("%d\t",arrs[i]);
        }
        System.out.println();
        ForkJoinTask<?> task = ForkJoinTask.adapt(new RunnTOForkJoin("R",0,arrs.length,arrs));
        pool.invoke(task);
        
        for(int i=20;i<30;i++) {
            System.out.printf("%d\t",arrs[i]);
        }
        System.out.println();
        
    }
20	21	22	23	24	25	26	27	28	29	
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
R 每一次最小单位的结果
4	4	4	4	4	5	5	5	5	5	

ForkJoinPool 的toString
   while(!task.isDone()) {
            System.out.println(pool);
        }
java.util.concurrent.ForkJoinPool@7f31245a[Running, parallelism = 4, size = 1, active = 1, running = 1, steals = 0, tasks = 0, submissions = 0]
关闭池

pool.shutdown()

pool.shutdownNow() 立即关闭

Fork/Join 框架注意事项

  1. 不使用同步方法或者同步代码块
  2. 尽量的分而治之
  3. 界限值不要太低
  4. 避免IO操作划分成很多块
  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值