目录:
1.Java中什么是多线程
2.什么叫多线程?Java支持多线程有何意义
3.java多线程的定义
4.java多线程编程核心技术豆瓣
5.java中实现多线程的几种方法
6.java多线程菜鸟教程
7.java多线程编程实战指南豆瓣
8.Java多线程详解
9.java多线程类
10.Java多线程是什么
1.Java中什么是多线程
目录线程池处理Runnable任务线程池处理Callable任务Executors的工具类构建线程池对象引言通过前面的学习,我们已经学会了线程是如何创建的以及线程的常用方法,接下来呢,我们将要深入性了解线程中的知识,主要是线程安全,线程同步,线程池三个知识点。
2.什么叫多线程?Java支持多线程有何意义
我相信大家通过这节课的简单地学习,就可以大概地掌握了线程吧!好了,废话不多说,我们开始今天的学习吧!
3.java多线程的定义
线程安全首先我们应该了解的是什么是“ 线程安全 ”问题呢?通俗易懂的讲的话,那就是“假设在某地有一瓶水,石原里美和工藤静香都很渴,想要去喝这瓶水,然而当这两个线程同时启动的时候,二人都会去拿这瓶水,并且同时判断这瓶水是否还在?在这瓶水未被取走之前,二人的判断都是true,因此二人都能够取到这瓶水,可是明明只有一瓶水,却可以让两个人都取到水,这很明显是与现实生活中的情况是不符合的。
4.java多线程编程核心技术豆瓣
”这就是我们需要处理的“线程安全”问题线程安全问题出现的原因:存在多线程并发同时访问共享资源存在修改共享资源
5.java中实现多线程的几种方法
实战模拟问题描述:仍然是前面的例子,现有两人需要喝水,分别是石原里美和工藤静香,二者共享同一瓶水,若对方喝掉这瓶水,则另一方则没有水可以喝具体操作:1、提供一个Account类并创建它,作为二人的共享水资源账户;。
6.java多线程菜鸟教程
publicclassAccount {privateint num;//代表水的数量publicAccount(){ } publicAccount(int num){
7.java多线程编程实战指南豆瓣
this.num = num; } publicintgetNum(){ return num; } publicvoidsetNum(int num)
8.Java多线程详解
{ this.num = num; } }2、定义一个线程类,并且该线程可以处理Account对象;publicclassThreadAccountextendsThread{
9.java多线程类
private Account account; publicThreadAccount() { } publicThreadAccount(Account account)
10.Java多线程是什么
{ this.account = account; } public Account getAccount() { return account; }
publicvoidsetAccount(Account account) { this.account = account; } @Override public
voidrun() { Thread thread = Thread.currentThread(); if(account.getNum()>0){ System.
out.println(thread.getName()+”已经成功获得了这瓶水!”); account.setNum(account.getNum()-1); System.
out.println(“此时还剩下”+account.getNum()+”瓶水”); }else { System.out.println(“水资源不够,已经无法取出”
); } } }3、创建两个线程,并传入同一个Account对象;publicstaticvoidmain(String[] args)throws Exception { Account account =
new Account(1); ThreadAccount threadAccount1 = new ThreadAccount(account); ThreadAccount threadAccount2 =
new ThreadAccount(account); Thread thread1 = new Thread(threadAccount1,”石原里美”); Thread thread2 =
new Thread(threadAccount1,”工藤静香”); thread1.start(); thread2.start(); }4、启动两个线程,同时获取同一瓶水。
通过运行结果,我们可以清晰的看出来存在很大的问题,当第一个人石原里美获得这瓶水的时候,水资源账户中已经没有水了,所以工藤静香是不能够取到水资源的,然而工藤静香仍然获得了水,且剩下了-1瓶水,这很明显是不符合现实情况的,那么我们该如何解决呢?
线程同步为了能够解决刚才出现的问题,我们可以考虑使用线程同步,让多个线程实现先后依次访问共享资源其核心思想是: 加锁 ,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来通俗易懂的讲就是:“假如两个线程同时开始访问共享资源,在访问之前,谁先拿到钥匙打开这把锁,谁才能访问该共享资源。
而另一个线程则只能在共享资源外等待钥匙空下来”接下来介绍几种方式来解决该问题
方式一:同步代码块作用: 把出现线程安全问题的核心代码给上锁原理:每次只能一个线程进入,执行完毕后自动解锁,其他进程才可以进来执行synchronized (同步锁对象){ 操作共享资源的代码(核心代码) }
锁对象要求:理论上,锁对象只要对于当前同时执行的线程来说是 同一个对象 即可synchronized (“喝水”) {//喝水是对于两个线程的不变对象if(account.getNum()>0){ 。
System.out.println(thread.getName()+”已经成功获得了这瓶水!”); account.setNum(account.getNum()-1
); System.out.println(“此时还剩下”+account.getNum()+”瓶水”); }else {
System.out.println(“水资源不够,已经无法取出”); } }具体的操作就是将之前的run()方法中的核心代码加锁,即可实现多个线程依次访问共享资源
其中需要注意的一点是,同步锁对象等同于打开共享资源的一把钥匙,所以应该对多个线程是同一个对象,并且要规范命名,若同步锁对象命名相同,则会影响另一组线程对共享资源的访问对于实例方法建议使用this作为锁对象;对于静态方法建议使用字节码(类名.class)对象作为锁对象。
方式二:同步方法作用: 把出现线程问题的核心方法给上锁原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行修饰符 synchronized 返回值类型 方法名称(形参列表){ 操作共享资源的代码 }。
与方式一的不同之处在于,前者是封装共享资源的核心代码,后者则是封装整个方法public synchronized voidLockWater(){ if(account.getNum()>
0){ System.out.println(thread.getName()+”已经成功获得了这瓶水!”); account.setNum(account.getNum()
-1); System.out.println(“此时还剩下”+account.getNum()+”瓶水”); }else { System.
out.println(“水资源不够,已经无法取出”); } }如果方法是实例方法:同步方法默认用this作为锁对象,但是代码要高度面向对象;如果方法是静态方法:同步方法默认用类名.class作为锁对象。
方式三:Lock锁为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock,更加灵活、方便Lock实现提供比使用 synchronized 方法和语句可以获得更广泛的锁操作Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建锁对象
方法名称说明public ReentrantLock( )获得Lock锁的实现类对象void lock( )获得锁void unlock( )释放锁//在使用之前先定义一个锁对象private Lock
lock = new ReentrantLock(); //定义过锁对象之后,即可以调用其APIlock.lock(); //共享资源代码lock.unlock();
线程池线程池是一个可以复用线程的技术;如果不使用线程池的话,用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销很大,这样会严重影响系统性能线程池的实现原理:。
在创建线程池时,设定该线程池固定存在N个 核心线程 用于处理任务,另外会有一个 任务队列 提供给任务排队等待,在任务队列中的前N个任务则是交给核心线程去处理,在没有空余线程的时候,其余任务则在任务队列中等待。
如何得到线程池对象?方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象;方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程对象。
ThreadPoolExecutor构造器的参数说明publicThreadPoolExecutor(int corePoolSize,intmaximumPoolSize,longkeepAliveTime,
TimeUnitunit,BlockingQueueworkQueue,ThreadFactorythreadFactory,RejectedExecutionHandlerhandler)
参数一:指定线程池的线程数量(核心线程): corePoolSize (不能小于0)参数二:指定线程池可支持的最大线程数: maximumPoolSize (最大数量>=核心线程)参数三:指定临时线程的最大存活时间: keepAliveTime (不能小于0)
参数四:指定存活时间的单位(秒、分、时、天): unit (时间单位)参数五:指定任务队列: workQueue (不能为null)参数六:指定用哪个线程工厂创建线程: threadFactory (不能为null)
参数七:指定线程忙,任务满的时候,新任务来了怎么办: handler (不能为null)为了更好的去理解多线程:我们可以假设 核心线程 数量为3个, 最大线程 数为5个,那么该线程池可以创建的 临时线程 数为5-3=2个线程,临时线程的最大存活时间是指其被创建之后不处理任务之后的存活时间,时间单位结合实际即可, 任务队列 设置为5个,参数六字面意思理解即可,参数七则是规定线程池不能再接收任务的时候如何处理。
接下来通过这两个问题加深理解临时线程什么时候创建?新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程(此时3个核心线程在处理任务,并且任务队列中已经有5个任务在等待了,然而仍然有任务过来,此时即可开始创建临时线程处理任务)。
什么时候会开始拒绝任务?核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝(当3个核心线程和2个临时线程都在处理任务,且任务队列满的情况下,将会开始拒绝接收任务,由参数七决定该如何处理,由此我们也可以得出该线程池任务处理的最大数量为:3+2+5=10,即核心线程+临时线程+任务队列)。
线程池处理Runnable任务ThreadPoolExecutor创建线程池对象:ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
3,5,10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());ExecutorService常用方法常用方法说明void executor(Runnable command)执行任务/命令,没有返回值。
一般用来执行Runnable任务Futuresubmit(Callable task)执行任务,返回未来任务对象获取线程结果,一般拿来执行Callable任务void shutdown( )
等任务执行完毕后关闭线程池List立刻关闭,停止正在执行的任务,并返回队列中未执行的任务参数七新任务拒绝策略策略说明ThreadPoolExecutor.AbortPolicy
丢弃任务,并抛出RejectExecutionException异常,默认的策略ThreadPoolExecutor.DiscardPolicy丢弃任务,但是不抛出异常,不推荐ThreadPoolExecutor.DiscardOldPolicy
抛弃队列中等待最久的任务,然后把当前任务加到队列中ThreadPoolExecutor.CallerRunsPolicy由主线程负责调用任务的run()方法从而绕过线程池直接执行//main方法public
staticvoidmain(String[] args){ ThreadPoolExecutor pool = new ThreadPoolExecutor(2,4,10, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); Runnable target =
new MyThreadRunnable(); //核心线程+任务队列=5,所以5个以内不需要创建临时线程 pool.execute(target); pool.execute(target); pool.execute(target); pool.execute(target); pool.execute(target);
//当任务数量达到5个的时候,接收任务的时候就需要创建临时线程 pool.execute(target); pool.execute(target); //当超过7个线程时,再次接收任务时,则会拒绝
pool.execute(target); } //实现Runnable接口publicclassMyThreadRunnableimplementsRunnable{
@Overridepublicvoidrun(){ System.out.println(Thread.currentThread().getName()+”正在处理任务”); Thread.sleep(
10000000);//避免线程快速处理任务,无法达到实验效果 } } //输出结果://pool-1-thread-2正在处理任务//pool-1-thread-4正在处理任务//pool-1-thread-3正在处理任务
//pool-1-thread-1正在处理任务
线程池处理Callable任务Futuresubmit(Callable task)执行任务,返回未来任务对象获取线程结果,一般拿来执行Callable任务//main方法publicclass
MoreThread{ publicstaticvoidmain(String[] args)throws Exception{ ThreadPoolExecutor pool =
new ThreadPoolExecutor(2,4,10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()); Future f1 = pool.submit(new MyThreadCallable()); Future f2 = pool.submit(
new MyThreadCallable()); Future f3 = pool.submit(new MyThreadCallable()); Future f4 = pool.submit(
new MyThreadCallable()); System.out.println(f1.get()); System.out.println(f2.get()); System.out.println(f3.get()); System.out.println(f4.get()); } }
//线程实现Callable接口publicclassMyThreadCallableimplementsCallable { @Overridepublic String call
()throws Exception { return Thread.currentThread().getName()+”正在工作中~”; } } //输出结果:仅由两个核心线程完成即可
//pool-1-thread-1正在工作中~//pool-1-thread-2正在工作中~//pool-1-thread-2正在工作中~//pool-1-thread-2正在工作中~
Executors的工具类构建线程池对象Executors:线程池的工具类通过调用方法返回不同类型的线程池对象方法名称说明public static ExecutorsService newCachedThreadPool( )。
线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉public static ExecutorsService newFixedThreadPool(int nThread)创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
public static ExecutorsService newSingleThreadExecutor( )创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程public static ScheduledExecutorsService newScheduledThreadPool(int corePoolSize)。
创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务注意:Executors的底层其实也是基于线程池的实现类ThreadPoolExecutor创建线程池对象ExecutorService pool1 = Executors.newFixedThreadPool(5); pool.execute(。
new MyThreadRunnable()); pool.execute(new MyThreadRunnable()); pool.execute(new MyThreadRunnable());虽然Executors使用起来会很方便,但是仍然是存在风险的,因此还是推荐前面使用的线程池创建方式。
(1)FixedThreadPool和SingleThreadExecutor:允许的请求队列长度为Integer.Max_VALUE,可能会堆积大量的请求,从而导致oom(2)CachedThreadPool和ScheduledThreadPool:。
允许的创建线程数量为Integer.Max.VALUE,可能会创建大量的线程,从而导致oom。创作不易,给个三连
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容