从来就没有救世主  也不靠神仙皇帝  要创造人类的幸福  全靠我们自己  

java 并发

 

1. 进程与线程

(1)进程

  进程时程序的一次执行,是系统进行资源分配的基本单位,每个进程有自己独立的内存空间的系统资源

(2)线程

  由于进程切换时间、空间开销大,引入线程提高执行效率

  系统进行调度的最小单位

(3)协程

  在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换

 

2. 上下文切换

  系统在发生任务切换时,要保存前一个任务的状态,以便下次切换回这个任务时能正确运行。保存状态、重新加载,就发生了上下文切换

 

(1)减小上下文切换

  ①无锁并发编程:

    多线程竞争锁时,会引起上下文切换。用其他办法避免使用锁。

  ②CAS算法:

    Java的 atomic 包使用CAS算法更新数据,不需要加锁

  ③尽量使用最少的线程

  ④协程

 

3. 死锁

  引起死锁的原因:

    当前线程拥有其它线程需要的资源

    当前线程等待其它线程占有的资源

    都不放弃已占有的资源

  解决死锁:

    避免一个线程同时获取多个锁

    避免一个线程在锁内通知占用多个资源,尽量保证每个锁只占用一个资源

    使用定时锁

    对于数据库锁,加锁和解锁在同一个数据库连接里进行

 

4. 

(1)原子性

  一个或多个操作,要么全部执行,且执行过程不会被打断。要么全部不执行。

(2)可见性

  多个线程访问同一个变量,一个线程修改了值,则其他线程要能够立即看得到修改后的值

(3)有序性

  程序执行的顺序要按代码先后顺序执行

 

5. java 并发 底层

  5.1 volatile

  保证不同线程对共享变量操作的可见性(一个线程修改了某个变量的值,其他线程不从缓存而直接去内存取值)

  比sunchronized的使用成本更低,不会引起线程上下文切换和调度

  5.2 synchronized

  普通同步方法:锁是当前实例对象

  静态同步方法:锁是当前类的Class对象

  同步方法块:

  5.3 原子操作

 

6. 线程

  6.1 线程状态

  NEW:初始状态,线程构建了,还没有调用start方法

  RUNNABLE:运行状态,包括就绪状态和运行状态

  BLOCKED:阻塞状态(请求锁而没有获得锁)

  WAITING:等待状态,当前线程需要等待其他线程的通知或中断

  TIME_WAITING:超时等待状态,等待指定时间后自行返回

  TERMINATED:终止状态

 

  

  6.2 中断 

 

 

 

  6.3 线程通信

(1)实现线程同步的 volatile、synchronized

  

(2)等待、通知

  Object类提供了 wait、notify方法

  线程A调用对象O的wait方法进入等待状态;线程B调用对象O的notify方法,线程A收到通知从对象O的wait方法返回,进行后续操作

package com;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Outer {
    static boolean flag =true;
    static Object lock = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(new Thread1(),"线程A");
        Thread thread2 = new Thread(new Thread2(),"线程B");
        thread1.start();
        thread2.start();
    }

    static class Thread1 implements Runnable{
        @Override
        public void run() {
            synchronized (lock) {
                while(flag) { //当前线程不满足执行条件
                    try {
                        System.out.println(Thread.currentThread()+":flag is true.wait at "
                                +new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait(); //进入等待状态,释放锁lock
                    }catch (InterruptedException e) {

                    }
                }
                //条件满足,继续工作
                System.out.println(Thread.currentThread()+":flag is false.running at "
                        +new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }

    static class Thread2 implements Runnable  {
        @Override
        public void run() {
            synchronized (lock) {
                //另一个线程发出通知,当前代码块执行完才释放锁lock
                System.out.println(Thread.currentThread()+" hold lock.notify at "
                        +new SimpleDateFormat("HH:mm:ss").format(new Date()));
                lock.notifyAll();
                flag = false;
            }
        }
    }
}

  线程A执行时,由于条件不满足,于是调用对象lock的wait,线程A进程等待,释放锁。

  等到线程B执行,修改条件,发出通知,释放锁,线程A从wait返回,继续工作。

 

  ①使用wait、notify时需要先对调用对象加锁

  ②调用wait后,线程由 RUNNING 变为 WAITING,当前线程进入等待队列

  ③notify后,等待线程不会立刻从wait返回,需要等到调用notify的线程释放锁后,等待线程才有机会从wait返回

  ④notify方法是将等待队列中的一个等待线程从等待队列移到同步队列中,即从 WAITING 变为 BLOCKED  

  ⑤线程要从wait返回,需要先获得调用对象的锁

  可见,等待--通知需要依赖于同步机制,才能确保等待线程从wait返回时能感知到通知线程对变量/标识做的修改

  

 

  等待(消费者)-----通知(生产者):

    消费者:①获取对象锁 ②条件不满足则调用对象的wait  ③条件满足则开始真正的工作   获得通知后,依然要检查条件

synchronized(对象) {
    while(条件不满足) {
        对象.wait();
    }
    真正的工作内容
}

 

    生产者:①获得对象锁 ②改变条件 ③通知所有等待在对象上的线程 

synchronized(对象) {
    改变条件
    对象.notifyAll();
}

 

 

(3)管道输入输出流

  PipedInputStream、PipedOutputStream、PipedReader、PipedWriter

  

package com;

import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;


public class Outer {

    public static void main(String[] args) throws IOException {
        PipedWriter out = new PipedWriter();
        PipedReader in = new PipedReader();
        out.connect(in);
        Thread thread1 = new Thread(new Thread1(in));
        thread1.start();

        out.write("message");
        out.close();
    }

    static class Thread1 implements Runnable {
        private PipedReader in;
        public Thread1(PipedReader in) {
            this.in = in;
        }
        @Override
        public void run() {
            int receive = 0;
            char[] buf = new char[100];
            try{
                while((receive = in.read(buf)) != -1) {
                    System.out.println("收到别的线程的管道消息:"+new String(buf,0,receive));
                }
            }catch(IOException ex) {

            }finally {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 

(4)Thread的join

  在线程A里调用线程B的join方法,则线程B会先执行,然后再执行A

  例子:

    在主线程里创建10个线程,是他们按序执行(main先执行,然后线程1,然后线程2....)

 

public class Outer {

    public static void main(String[] args) throws InterruptedException {
        Thread previous = Thread.currentThread(); //main线程
        for(int i=1;i<=10;i++) {
            Thread thread = new Thread(new Thread1(previous),"线程"+i);
            thread.start();
            previous = thread;
        }
        //main线程等待一会
        Thread.currentThread().sleep(5);
        System.out.println(Thread.currentThread().getName()+" 执行完了");
    }

    static class Thread1 implements Runnable {
        private Thread thread;
        public Thread1(Thread thread) {
            this.thread = thread;
        }
        @Override
        public void run() {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+" 执行完了");
        }
    }
}

 

  这个join方法其实也是 等待--通知类型的:在各个线程里调用上一个线程的join方法如下

    

 

  以此为例,线程1调用了main线程的wait方法,线程1进入等待状态;线程2调用线程1的join方法,线程2进入等待状态.....。   线程终止时,会调用自身的 notifyAll方法。

  main线程终止,调用了notifyAll,而且条件变化(isAlive变化了),线程1从等待队列到了同步队列。此时,线程1可以继续执行下去了。

  

(5)ThreadLocal

  线程变量,一个以 ThreadLocal对象为键、任意对象为值的结构,这个结构附带在线程上。相当于线程内部的一个局部变量。

  例子:计算线程运行时间

public class Outer {
    private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<Long>(){
        //如果没有调set方法,则掉get方法时会调用此方法进行初始化
            protected Long initialValue() {
                return System.currentTimeMillis();
            }
    };

    public static void main(String[] args) throws InterruptedException {
        Outer.begin();
        Thread.currentThread().sleep(1);
        System.out.println("消耗时间 "+Outer.end() + "秒");
    }

    public static void begin(){
        TIME_THREADLOCAL.set(System.currentTimeMillis());
    }
    public static long end(){
        long res = System.currentTimeMillis()-TIME_THREADLOCAL.get();
        TIME_THREADLOCAL.remove(); //记得不用了删除这个变量
        return res;
    }
}

 

 

7. ThreadLocal的作用

(1)如6的(5),线程内部的变量,可用来传递一些信息

(2)在数据库连接池中,用一个线程管理一个Connection

  在连接池中,如何保证一个线程操作一个Connection来保证事务:一个线程在创建Connection时,将其放入线程的ThreadLocal的值里面,关闭连接时取出来

 

(3)避免不必要的参数传递

  

  

 =================================================================================

8. 锁

  8.1 synchrinized锁

  从类型上看是一种互斥锁:一次只允许一个线程进入被锁住的代码块

  java中每个对象都有一个内置锁(监视器),synchronized使用对象的内置锁来将代码块锁定

 

  这个关键字保证了线程的原子性、可见性

 

  在普通方法、代码块上使用这个关键字,使用的是对象锁,也可以专门创建一个对象成员,用这个成员作为锁。

  静态方法、代码块用的是类的字节码文件对象作为锁。

  

  类锁和对象锁是不冲突的:两个线程,一个获取对象锁,一个获取类锁,实际上两个线程获取的是不同的锁,不会导致另一个的休眠

 

  8.2 java.util.concurrent.locks.Lock 接口

  类似synchronized,但可以:①尝试非阻塞获取锁 ②获取锁的线程能响应中断 ③获取锁设定超时时间

  使用简例:

Lock lock = new ReentrantLock();
lock.lock();
try{
    xxx
}catch(){
    xxxx
}finally{
    lock.unlock();
}

  加锁的操作不能放在try里,防止获取锁时发生异常,没加成锁,却执行了解锁的操作。

 

  接口提供的方法:

void lock()  获取锁
void lockInterruptibly()  可中断的获取锁
boolean tryLock()  尝试非阻塞获取锁
boolean tryLock(long time, TimeUnit unit) 超时、未超时而被中断、未超时获取到了 会返回
void unlock()
Condition newCondition()  获取等待通知组件,该组件和当前锁绑定,只有线程获取了锁,才能调用该组件的wait方法,调用后,当前线程会释放锁

 

  8.3 AQS

  

  队列同步器,用来协助Lock的实现类来实现锁或其他同步组件(作为Lock实现类的内部静态类)

  使用一个int成员变量表示同步状态,通过内置的FIFO队列完成资源获取线程的排队工作

 

  公平锁:线程按发出请求的顺序获取锁

  非公平锁:可以插队获取锁(Lock、synchronized默认)

 

 

  8.4 ReentrantLock

  重入锁 :已经获取锁了再次获取锁,不会导致自己阻塞

  已占有这个锁的线程再次获取锁,只会导致锁内部的计数器加1。对应的,n次获取锁就要n次释放锁。当计数为0时,锁才算释放。

 

  构造:默认是非公平锁  传入true是公平锁;传false是非公平锁

 

  互斥锁

 

  8.5 ReentrantReadWriteLock读写锁

  读数据时,允许多个线程进入锁定区域   写数据时,不允许其他线程读或写

  特点:

    ①默认非公平,也有公平锁的选择

    ②重入。读线程获取了读锁后可再次获取读锁;写线程获取写锁后能再次获取写锁,也可以获取读锁

    ③降级锁。写锁能降级成读锁。

    ④读锁不支持条件对象;写锁支持条件对象

 

  获取锁:ReadWriteLock接口提供

Lock readLock()
Lock writeLock()

  其它:

int getReadLockCount()  获取读锁被获取次数
int getReadHoldCount()  当前线程获取读锁的次数
boolean isWriteLocked() 写锁是否被获取
int getWriteHoldCount() 当前线程获取写锁的次数

 

 

9. 并发容器和框架

  9.1 

(1)java.util.concurrent.ConcurrentHashMap

  HashTable使用 synchronized 保证线程安全,效率较低(多个线程竞争同一个锁)

  ConcurrentHashMap使用锁分段技术(将数据分成多个段,每段配一个锁,只有多个线程访问同一个段时才表现为竞争),效率高些

 

  ConcurrentHashMap扩容,每次增长1倍

 

(2)非阻塞队列

  ①ConcurrentLinkedQueue

  线程安全队列

  ②ConcurrentLinkedDeque

  线程安全双端队列

 

(3)阻塞队列

  支持阻塞的添加:队列满时,队列会阻塞试图再添加元素的线程,知道队列有空位置

  支持阻塞的移除:队列空时,队列会阻塞视图获取元素的线程

 

  对添加和移除的处理:对无界阻塞队列,不会出现队列满的情况

    

 

 

  java的阻塞队列:

    ①ArrayBlockingQueue  有界阻塞队列

    ②LinkedBlockingQueue  有界阻塞队列

    ③LinkedBlockingDeque  双向阻塞队列

    ④PriorityBlockingQueue  无界优先队列

    ⑤DelayQueue   支持延时获取元素的无界阻塞队列

    ⑥SynchronousQueue  不存储元素的阻塞队列

    ⑦LinkedTransferQueue  无界阻塞队列     

 

 

 

10. 原子操作/原子变量类

  java.util.concurrent.atomic

  10.1 基本类型

AtomicBoolean
AtomicInteger
AtomicLong

  AtomicInteger的操作:其它两个类似

int addAndGet(int delta) 原子性的将delta与AtomicInteger里的value相加,返回结果
boolean compareAndSet(int expect,int update) 如果原来的数值等于expect,则将AtomicInteger里面的value设为update
int getAndIncrement() 后置自增 x++
int getAndDecrement() 后置自减 x--
int incrementAndGet() 前置自增 ++x
int decrementAndGet() 前置自减 --x
void lazySet(int newValue)  最终将数值设为newValue(可能导致其它线程在此操作后一小段时间内读到旧值)
int getAndSet(int newValue) 设置新值,返回旧值

 

  10.2 数组类型

  原子性的更新数组里的某个元素

AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray

 

  数组通过构造函数传数组进去,之后AtomicXxxArray会将数组复制到自己的array成员上,对内部数组的修改不影响传入的数组

 

  10.3 引用类型

  原子性的更新引用类型

AtomicReference
AtomicStampedReference  带版本号的引用类型
AtomicMarkableReference 带标记位的引用类型

 

  例:

import java.util.concurrent.atomic.*;

public class Outer {
    public static void main(String[] args) throws InterruptedException {
        AtomicReference<User> atomicReference = new AtomicReference<User>();
        User user1 = new User("name1",20);
        atomicReference.set(user1);
        System.out.println(atomicReference.get().getName()); //name1
        System.out.println(atomicReference.get().getAge());  //20

        User user2 = new User("name2",30);
        atomicReference.compareAndSet(user1,user2);
        System.out.println(atomicReference.get().getName()); //name2
        System.out.println(atomicReference.get().getAge());  //30
    }
    static class User{
        private String name;
        private int age;
        public User(String name,int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }

}

 

 

  10.4 原子更新对象属性

AtomicIntegerFieldUpdate 原子更新整型的字段的更新器
AtomicLongFieldUpdate
AtomicReferenceFieldUpdate

  以上三个是抽象类,使用时:①用静态方法newUpdate() 创建一个更新器,传入类的class和字段名字

                 ②字段必须是 public volatile的

package com;


import java.util.concurrent.atomic.*;


public class Outer {
    public static void main(String[] args) throws InterruptedException {
        AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class,"age");
        User user1 = new User("name1",20);
        System.out.println(a.incrementAndGet(user1));
    }
    static class User{
        private String name;
        public volatile int age;
        public User(String name,int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }

}

 

  10.5 jdk8新增的

  高并发环境下比AtomicLong更高效

DoubleAccumulator
LongAccumulator
DoubleAdder
LongAdder

 

 

 

11. 线程池

  11.1 线程池的处理流程:

  

 

 

  11.2 jdk中提供的线程池继承体系:

   

 

  最常用的是ThreadPoolExecutor

  ScheduledThreadPoolExecutor在ThreadPoolExecutor的基础上加了"延迟"、"周期执行"的功能

  ForkJoinPool是jdk1.7新增的线程池,与ThreadPoolExecutor区别在于工作采用的算法不同 

 

  11.3 ThreadPoolExecutor

(1)线程池创建

ThreadPoolExecutor(int corePoolSize,                    //线程池基本大小
                   int maximumPoolSize,                 //线程池最大数量
                   long keepAliveTime,                  //线程活动保持时间(线程空闲后保持存活的时间)
                   TimeUnit unit,                       //活动保持时间的单位(天、小时、分钟、毫秒、微妙、纳秒)
                   BlockingQueue<Runnable> workQueue,   //任务队列,保存等待执行的任务的阻塞队列
                   ThreadFactory threadFactory,         //用于设置创建线程的工厂(guava框架)
                   RejectedExecutionHandler handler)    //饱和策略(队列和线程池都满了时)

 

   JDK提供了Executors类来创建线程池:

newFixedThreadPool   固定线程数的线程池 corePoolSize和maximumPoolSize相等
newCachedThreadPool  对于新任务,若池中无空闲线程,线程池会立刻去创建新线程处理任务 最大线程数为 Integer.MAX_VALUE
SingleThreadExecutor 池中只有1个线程

 

  池的状态:

    RUNNING:线程池能接受新任务

    SHUTDOWN:线程池 不可以接受新任务,对已添加的任务还会进行处理

    STOP:线程池不接受新任务,不处理已添加的任务,中断增在处理的任务

    TIDYING:所有任务已终止。调用钩子函数 terminated()  此函数可自定义

    TERMINATED:线程池彻底终止

 

 

 

  关于线程数量:

    corePoolSize:线程池的基本大小,但并不会一开始就创建这么多个线程(除非执行了prestartAllThreads())。

                  提交任务到线程池,若当前线程数少于基本大小,则创建新线程执行任务(即使池中有空闲线程)  ----按 11.1 的图

             

(2)向线程池提交任务

void execute(Runnable command)
Future<?> submit(Runnable task)

  execure:无返回值

  submit:用Future的get() 方法获取返回值,get会阻塞当前线程直到任务完成

 

(3)关闭线程池

  都是逐个调用线程的 interrupt 方法中断线程

void shutdown():将池状态设为SHUTDOWN,然后中断所有没有执行任务的线程
List<Runnable> shutdownNow方法:将池状态设为STOP,然后调用所有正在执行或暂停任务的线程,返回等待执行任务的列表

 

 

 

 

12. 工具类

12.1 锁相关

(1)LockSupport

  可实现阻塞线程、唤醒线程

  

 

  新的API在个方法参数中增加了Object  blocker,即阻塞对象,可用于问题排查和系统监控

 

12.2 控制流程相关

(1)CountDownLatch

  同步辅助类,允许一个或多个线程一直等待,直达其它线程完成工作(封装了join方法)

CountDownLatch(int N)      等待N个点完成
void await()               阻塞当前线程,直到N变为0
boolean await(long timeout, TimeUnit unit) 
void countDown()           N减1
long getCount()

  countDown可用在N个线程或一个线程的N个步骤里,看需求而定

  例子:让线程A等待5个线程

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;


public class Outer {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        CountDownLatch countDownLatch = new CountDownLatch(5);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("其他线程结束了 "+Thread.currentThread().getName()+" 才结束");
            }
        },"A线程").start();
        for(int i=1;i<=5;i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+" 结束了");
                    countDownLatch.countDown();
                }
            },"线程"+i).start();
        }
    }
}

 

(2)CyclicBarrier  同步屏障

  让一组线程到达一个屏障(同步点)时被阻塞,直到所有线程到达屏障时,屏蔽开门,所有被拦截的线程才会继续允许执行下去

  所有等待线程释放后,CyclicBarrier可重用(CountDownLatch不能重用)

  CyclicBarrier和CounrDownLatch对比:

    CountDownLatch注重:等待其它线程完成

    CyclicBarrier:当线程到达某个状态后,等待其它线程,所有线程都到达后,再一起继续执行

CyclicBarrier(int parties, Runnable barrierAction)
CyclicBarrier(int parties) 
int await()    调用的线程到达屏障,调用线程阻塞
int await(long timeout, TimeUnit unit)
void reset() 重置计数器,让线程重新执行一次

 

  例子:三个线程,完成第一阶段工作后要等其它线程,然后才进行第二阶段工作

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;


public class Outer {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        for(int i=1;i<=3;i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"完成第一阶段工作,等待其它线程");
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"其它线程都完成了第一阶段工作,继续第二阶段工作");
                }
            },"线程"+i).start();
        }
    }
}

 

  

(3)Semaphore

  控制同时访问特定资源线程的数量(流量控制:数据库连接)

Semaphore(int permits)      允许同时访问的线程数(许可证数)
Semaphore(int permits, boolean fair)
void acquire()              消费一个许可证,没有许可证时线程阻塞
void acquire(int permits)
void release()              归还一个许可证
void release(int permits)
boolean tryAcquire()
boolean tryAcquire(int permits)
boolean tryAcquire(long timeout, TimeUnit unit)
boolean tryAcquire(int permits, long timeout, TimeUnit unit)
int availablePermits()     当前可用许可证数
int getQueueLength()       正在等待获取许可证的线程数
boolean hasQueuedThreads() 是否有线程正在等待获取许可证
void reducePermits(int reduction) 减少许可证
Collection<Thread> getQueuedThreads() 获取所有等待获取许可证的线程的集合

 

  例子:商店购买商品,只允许4个人同时进去,现有8个人

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;


public class Outer {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Semaphore semaphore = new Semaphore(4);
        for(int i=1;i<=8;i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();  //拿一个许可证/餐桌号牌(拿到餐桌号牌了才能进去)
                        System.out.println(Thread.currentThread().getName()+" 挑选商品中...");
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName()+" 结算完毕");
                        semaphore.release(); //归还号牌
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"线程"+i).start();
        }
    }
}

 

 

12.3 线程数据交换

(1)Exchanger

  提供一个同步点,在同步点两线程可交换彼此的数据

  第一个线程执行 exchange() 方法,它会一直等待第二个线程也执行 exchange() 方法 

 

 

 

13. FutureTask

  异步计算结果

  实现了Runnable接口、Future接口。

(1)FutureTask状态

  

 

(2)在不同状态下调用get或cancel

  

 

(3)使用例子

package com;




import java.util.concurrent.*;
import java.util.concurrent.atomic.*;


public class Outer {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1
//        ExecutorService executor = Executors.newCachedThreadPool();
//        Task task = new Task();
//        Future<Integer> result = executor.submit(task);
//        executor.shutdown();
//        System.out.println("计算结果为:"+result.get());
//        System.out.println("main线程执行完毕");
        //2
//        ExecutorService executor = Executors.newCachedThreadPool();
//        Task task = new Task();
//        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
//        executor.submit(futureTask);
//        executor.shutdown();
//        System.out.println("计算结果为:"+futureTask.get());
//        System.out.println("main线程执行完毕");

        //3
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println("计算结果为:"+futureTask.get());
        System.out.println("main线程执行完毕");
    }

    static class Task implements Callable{

        @Override
        public Integer call() throws Exception {
            Thread.sleep(1000);
            int sum = 0;
            for(int i = 1;i<=100;i++) {
                sum += i;
            }
            System.out.println("子线程计算完毕");
            return sum;
        }
    }
}

 

   

   

  

 

 

 

 

 

 

 

 

  

posted @ 2020-06-19 08:08  T,X  阅读(188)  评论(0编辑  收藏  举报