zoukankan      html  css  js  c++  java
  • Callable接口及线程池

    线程池

    线程容器,可设定线程分配的数量上限。

    将预先创建线程对象存入池中,并重用线程池中的线程对象。

    避免频繁的的创建和销毁。

    常用的线程池接口和类

    Executor :线程池的顶级接口

    ExecutorService :线程池接口,可通过submit(Runnable task)提交任务代码。

    Executors工厂类:通过此类可获得一个线程池。

    ​ 通过newFixedThreadPool(int nThreads)获取固定数量的线程池。

    ​ 通过newCachedThreadPool()获得动态数量的线程池,如果不够 则创建新的,没有上限。

    public class TestThreadPool {
    	public static void main(String[] args) {
    		//线程池接口(引用)    --->     Executors工具类(工厂类)
    		ExecutorService es = Executors.newFixedThreadPool(4);
    		
    		Runnable task = new MyTask();
    		
    		es.submit(task); //submit()提交任务
    		es.submit(task);
    		es.submit(task);
    		es.submit(task);
    	}
    }
    //创建接口实现类
    class MyTask implements Runnable{
    	@Override
    	public void run() {
    		for (int i = 0; i < 100; i++) {
    			System.out.println(Thread.currentThread().getName() + " - " +i);
    		}
    	}
    }
    

    Callable接口

    JDK5加入,与Runnable接口类似,实现之后代表一个线程任务。

    有泛型返回值,可以声明异常。

    Future接口

    概念:

    ​ 异步接收ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值。

    方法:

    ​ V get()以阻塞形式等待Future的异步处理结果(call()的返回值)

    使用

    线程池执行Callable接口,Callable返回值由Future接收,Future当中的get() 方法就可以得到异步返回值。

    可以解决并发下的一些统计工作。

    public class TestCallable {
    	public static void main(String[] args) throws InterruptedException, ExecutionException {
    		System.out.println("程序开始");
    		//创建线程池
    		ExecutorService ex = Executors.newFixedThreadPool(3);
    		//接口引用指向实现接口
    		Callable<Integer> task1 = new MyTask1();
    		Callable<Integer> task2 = new MyTask2();
    		
    		Future<Integer> f1 = ex.submit(task1);	//得到Callable线程接口的返回值
    		Future<Integer> f2 = ex.submit(task2);
    		
    		Integer result1 = f1.get(); //以阻塞形式等待Future中的异步处理结果(call的返回值)
    		Integer result2 = f2.get(); //在没有返回值以前,get无限期等待
    		
    		System.out.println(result1 + result2); //输出5050
    	}
    }
    //Mytask1类遵从Callable接口实现call()方法
    class MyTask1 implements Callable<Integer>{
    	@Override
    	public Integer call() throws Exception {
    		Thread.sleep(1000); //休眠1秒,观察Future接口get方法
    		Integer sum = 0;
    		for (int i = 1; i <= 50; i++) {
    			sum += i;
    		}
    		return sum; //返回计算的sum值
    	}
    }
    //Mytask2类遵从Callable接口实现call()方法
    class MyTask2 implements Callable<Integer>{
    	@Override
    	public Integer call() throws Exception {
    		Thread.sleep(1000);
    		Integer sum = 0;
    		for (int i = 51; i <= 100; i++) {
    			sum += i;
    		}
    		return sum; //返回计算的sum值
    	}
    }
    

    同步和异步的区别:

    同步:

    形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续。

    异步:

    形容一次方法调用,异步一旦开始,像是一次消息传递,调用者告知之后立刻返回。二者竞争时间片,并发执行。

    Lock接口

    提供更多实用性的方法,功能更强大,性能更优越。

    常用方法:

    void lock() - 获取锁,如锁被占用,则等待。

    boolean tryLock() - 尝试获取锁(成功返回true,失败返回false,不阻塞)

    void unlock() - 释放锁

    重入锁

    ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能。

    Lock locker = new ReentrantLock(); //创建重入锁对象
    locker.lock();	//开启锁
    try{
        锁住代码块
    }finally{
        //考虑可能会出现异常,释放锁必须放入finally代码块中,避免无法释放
        locker.unlock();	//释放锁
    }
    

    读写锁

    ReentrantReadWriteLock:

    • 一种支持一写多读的同步锁,读写分离,可分别分配读锁,写锁。

    • 支持多次分配读锁,使多个读操作可以并发执行。

    互斥规则:

    写 - 写:互斥,阻塞。

    读 - 写:互斥,读阻塞写,写阻塞读。

    读 - 读:不互斥,不阻塞。

    在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。

    //读写锁
    class Student {
        //创建读写锁对象
        ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
        //创建读锁
        ReentrantReadWriteLock.ReadLock readLock =rwl.readLock();
        //创建写锁
        ReentrantReadWriteLock.WriteLock writeLock = rwl.writeLock();
    
        private int value;  //属性
        //读方法
        public int getValue() throws InterruptedException {
            readLock.lock();    //开启读锁
            try {
                Thread.sleep(1000); //休眠1秒,观察读的时间
                return value;
            } finally {
                readLock.unlock();  //关闭读锁
            }
        }
        //写方法
        public void setValue(int value) throws InterruptedException {
            writeLock.lock();   //开启写锁
            try {
                Thread.sleep(1000);
                this.value = value;
            } finally {
                writeLock.unlock(); //关闭写锁
            }
        }
    }
    

    最后总结:多线程相关的新旧对比

  • 相关阅读:
    PAT (Advanced Level) Practice 1055 The World's Richest (25 分) (结构体排序)
    PAT (Advanced Level) Practice 1036 Boys vs Girls (25 分)
    PAT (Advanced Level) Practice 1028 List Sorting (25 分) (自定义排序)
    PAT (Advanced Level) Practice 1035 Password (20 分)
    PAT (Advanced Level) Practice 1019 General Palindromic Number (20 分) (进制转换,回文数)
    PAT (Advanced Level) Practice 1120 Friend Numbers (20 分) (set)
    从零开始吧
    Python GUI编程(TKinter)(简易计算器)
    PAT 基础编程题目集 6-7 统计某类完全平方数 (20 分)
    PAT (Advanced Level) Practice 1152 Google Recruitment (20 分)
  • 原文地址:https://www.cnblogs.com/MonkeySun/p/13336526.html
Copyright © 2011-2022 走看看