73 java多线程_5 _线程池

文章目录??线程池概念????线程池原理????创建线程池,线程池API????Callable接口????Callable的基本使用????Callable结合线程池的使用????Future接口????线程同步和异步????线程同步????线程异步????Lock接口(与synchronized)????Lock接口的实现类:ReentrantLock????ReadWriteLock接口:ReentrantReadWriteLock??线程池概念问题:线程是宝贵的内存资源、单个线程约占1MB空间,过多分配易造成内存溢出。频繁的创建及销毁线程会增加虚拟机回收频率、资源开销,造成程序性能下降。线程池:线程容器,可设定线程分配的数量上限。将预先创建的线程对象存入池中,并重用线程池中的线程对象。避免频繁的创建和销毁。线程池原理

将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程

创建线程池,线程池API

常用的线程池接口和类(所在包java. util. concurrent) :

Executor:线程池的顶级接口。ExecutorService:线程池接口,可通过submit (Runnable task) 提交任务代码。Executors工厂类:通过此类可以获得一个线程池。通过newFixedThreadPool (int nThreads) 获取固定数量的线程池。参数:指定线程池中线程的数量。通过newCachedThreadPool() 获得动态数量的线程池,如不够则创建新的,没有上限package com.wlw.thread.threaddemo02;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ThreadPoolExecutor;/** * 线程池的创建 * (1)Executor:线程池的根接口 —–> execute()执行 * (2)ExecutorService:包含了管理线程池的一些方法,submit,shutdown * 子类 ThreadPoolExecutor* 子类 ScheduledThreadPoolExecutor * (3)Executors:创建线程池的工具类 * (3.1)创建固定线程个数线程池 * (3.2)创建缓存(动态数量)线程池,由任务的多少决定 * (3.3)创建单线程池 * (3.4)创建调度线程池,调度:周期、定时执行 * */public class ThreadPoolDemo01 { public static void main(String[] args) { //1.1创建固定线程个数线程池 //ExecutorService executorService = Executors.newFixedThreadPool(4); //1.2创建缓存(动态数量)线程池,由任务的多少决定 ExecutorService executorService = Executors.newCachedThreadPool(); //1.3创建单线程池 //ExecutorService es = Executors.newSingleThreadExecutor(); //1.4创建调度线程池 //Executors.newScheduledThreadPool(4); //2.创建任务 Runnable runnable = new Runnable() { private int ticket = 100; @Override public void run() { while (true){ if(ticket <= 0){ break; } System.out.println(Thread.currentThread().getName()+”卖出了,第”+ticket+”张票”); ticket–; } } }; //3.提交任务(提交多次,分配多个线程) for (int i = 0; i < 4; i++) { executorService.submit(runnable); } //4.关闭线程池 executorService.shutdown();//等提交的任务全部执行完,关闭线程池,但不接受新任务。 //executorService.shutdownNow();//立即停止,不等待 }}Callable接口

线程创建的三种方式: 1. 通过继承Thread,重写run方法 2. 实现Runnable接口 3. 实现Callable接口 – jdk5加入,与Runnable接口类似,实现之后代表一个线程任务 – Callable具有泛型返回值、可以声明异常。

public interface Callable<V>{ public V call() throws Exception; }Callable的基本使用

注意:需要将Callable对象转换成可执行任务FutureTask(FutureTask 实现了Runnable接口),再传给线程

package com.wlw.thread.threaddemo02;import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;/** * 演示Callable接口的使用 * Callable接口与Runnable接口的区别: * (1)Callable接口中call方法具有泛型返回值,Runnable接口中的run方法没有返回值 * (2)Callable接口中call方法有声明异常,Runnable接口中的run方法没有声明异常 */public class CallableDemo { public static void main(String[] args) throws Exception { //功能需求:使用Callable实现1~100的和 //1.创建Callable对象 Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+”开始计算:”); int sum = 0; for (int i = 0; i <= 100; i++) { sum = sum + i; } return sum; } }; //2.将Callable对象转换成可执行任务(FutureTask 实现了Runnable接口) FutureTask<Integer> task = new FutureTask<>(callable); //3.创建线程对象,将任务传给线程 Thread thread = new Thread(task); //4.启动线程 thread.start(); //5.获取结果(get() 方法要等call() 方法执行完毕,才能返回) Integer integer = task.get(); System.out.println(integer); }}/*执行结果:Thread-0开始计算:5050*/Callable结合线程池的使用

注意:Callable对象是可以直接传给线程池的(不需要转换成FutureTask)

线程池.submit (线程池的提交)有返回值,为future : 表示将要执行完任务的结果

package com.wlw.thread.threaddemo02;import java.util.concurrent.*;/** * Callable结合线程池的使用 * Callable对象是可以直接传给线程池的(不需要转换成FutureTask) * 实现计算1~100的和 */public class ThreadPool_Callable_Demo { public static void main(String[] args) throws Exception { //1.创建线程池 ExecutorService es = Executors.newFixedThreadPool(1); //2.提交任务 es.submit 的返回值为future : 表示将要执行完任务的结果 Future<Integer> future = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName() + “开始计算”); int sum = 0; for (int i = 0; i <= 100; i++) { sum = sum + i; } return sum; } }); //3.获取结果 System.out.println(future.get()); //4.关闭线程池 es.shutdown(); }}Future接口Future:表示将要完成任务的结果表示ExecutorServ ice. submit ()所返回的状态结果,就是call()的返回值方法:V get() 以阻塞形式等待Future中的异步处理结果(call()的返回值)

需求:使用两个线程,并发计算150,51100的和,再进行汇总

package com.wlw.thread.threaddemo02;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * Future接口的使用 * 需求:使用两个线程,并发计算1~50,51~100的和,再进行汇总 */public class FutureDemo { public static void main(String[] args) throws Exception{ //1.创建线程池 ExecutorService es = Executors.newFixedThreadPool(2); //2.提交任务 Future<Integer> future1 = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+”计算开始”); int sum = 0; for (int i = 0; i <= 50; i++) { sum += i; } System.out.println(“1~50 计算完毕”); return sum; } }); Future<Integer> future2 = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+”计算开始”); int sum = 0; for (int i = 51; i <= 100; i++) { sum += i; } System.out.println(“51~100 计算完毕”); return sum; } }); //3.获取结果(get() 方法要等call() 方法执行完毕,才能返回) System.out.println(future1.get()+future2.get()); //4.关闭线程池 es.shutdown(); }}/*执行结果:pool-1-thread-1计算开始pool-1-thread-2计算开始51~100 计算完毕1~50 计算完毕5050*/线程同步和异步线程同步形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续

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

Lock接口(与synchronized)实现线程同步的接口JDK5加入,与 synchronized 比较, 显示定义,结构更灵活。提供更多实用性方法,功能更强大、性能更优越。常用方法:void lock() //获取锁,如锁被占用,则等待。boolean tryLock() //尝 试获取锁(成功返回true。失败返回false,不阻塞)void unlock() //释放锁Lock接口的实现类:ReentrantLock

重入锁:ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能(但比synchronized更强大)

例子1:

package com.wlw.thread.lock;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * ReentrantLock的使用 * 重入锁 */public class MyList { //创建锁 private Lock lock = new ReentrantLock(); private String[] str = {“A”,”B”,””,””,””}; int count = 2; public void add(String value){ try { lock.lock(); //上锁 str[count] = value; try { Thread.sleep(1000);//主动休眠1秒 } catch (InterruptedException e) { e.printStackTrace(); } count++; System.out.println(Thread.currentThread().getName()+”存入了”+value); }finally { lock.unlock();//解锁 } } public String[] getStr() { return str; }}package com.wlw.thread.lock;import java.util.Arrays;public class TestList { public static void main(String[] args) throws Exception { MyList list = new MyList(); Runnable runnable1 = new Runnable() { @Override public void run() { list.add(“Hello”); } }; Runnable runnable2 = new Runnable() { @Override public void run() { list.add(“World”); } }; //创建线程并启动 Thread t1 = new Thread(runnable1); Thread t2 = new Thread(runnable2); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(Arrays.toString(list.getStr())); }}/*Thread-0存入了HelloThread-1存入了World[A, B, Hello, World, ]*/

例子2:

package com.wlw.thread.lock;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Ticket implements Runnable{ private int ticket = 100; private Lock lock = new ReentrantLock(); @Override public void run() { while (true){ lock.lock(); try { if(ticket <= 0){ break; } System.out.println(Thread.currentThread().getName()+”卖了第”+ticket+”张票”); ticket–; } finally { lock.unlock(); } } }}package com.wlw.thread.lock;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestTicket { public static void main(String[] args) { //创建实现类对象 Ticket ticket = new Ticket(); //创建线程池 ExecutorService es = Executors.newFixedThreadPool(4); //提交任务 for (int i = 0; i < 4; i++) { es.submit(ticket); } //关闭线程池 es.shutdown(); }}ReadWriteLock接口:ReentrantReadWriteLock读写锁:ReentrantReadWriteLock:一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。支持多次分配读锁,使多个读操作可以并发执行。互斥规则:写-写:互斥,阻塞。读-写:互斥,读阻塞写、写阻塞读。读-读:不互斥、不阻塞。在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。package com.wlw.thread.lock;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import java.util.concurrent.locks.ReentrantReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;/** * 读写锁的演示 * ReentrantReadWriteLock * */public class ReadWriteDemo { //创建读写锁 private ReentrantReadWriteLock rrl= new ReentrantReadWriteLock(); //获取读锁 private ReadLock readLock = rrl.readLock(); //获取写锁 private WriteLock writeLock = rrl.writeLock(); //重入锁 private Lock lock = new ReentrantLock(); private String value; public String getValue(){ readLock.lock();//读锁,来上锁 //lock.lock(); try { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“读取了,”+value); return this.value; } finally { readLock.unlock(); //lock.unlock(); } } public void setValue(String value){ writeLock.lock();//写锁,上锁 //lock.lock(); try { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“写入了,”+value); this.value = value; } finally { writeLock.unlock(); //lock.unlock(); } }}package com.wlw.thread.lock;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestReadWrite { public static void main(String[] args) { //创建对象 ReadWriteDemo readWriteDemo = new ReadWriteDemo(); //创建线程池 ExecutorService es = Executors.newFixedThreadPool(20); Runnable read = new Runnable() { @Override public void run() { readWriteDemo.getValue(); } }; Runnable write = new Runnable() { @Override public void run() { readWriteDemo.setValue(“张三”+new Random().nextInt(100)); } }; long start = System.currentTimeMillis(); //提交2次写 for (int i = 0; i < 2; i++) { es.submit(write); } //提交18次读 for (int i = 0; i < 18; i++) { es.submit(read); } es.shutdown();//关闭 while (!es.isTerminated()){//判断所有线程是否都运行完毕,否则空转 } long end = System.currentTimeMillis(); System.out.println(“用时:”+(end – start)); }}/*读写锁与重入锁 两者用时比较:用时:3006 vs 用时:20013*/

【本文由:湖北阿里云代理 aliyun.html 复制请保留原URL】一个今天胜过两个明天

73 java多线程_5 _线程池

相关文章:

你感兴趣的文章:

标签云: