多线程实用讲解

1.线程生命周期

引用

2.Java中实现多线程的方法

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口,并用FutureTask包装类创建线程
    使用executorService,callable,future实现由返回结果的多线程

接口区别:
1)、实现Runnable无返回值,
2)、 实现Callable有返回值
方法区别:
1)、 execute() 方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
2)、 submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future 对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前 线程直到任务完成

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import cn.hutool.core.thread.ThreadUtil;
public class A {
	//继承Thred
	public class ThreadB extends Thread{
		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
		}
	}
	//实现Runnable
	public class ThreadC implements Runnable{
		@Override
		public void run() {
			// TODO Auto-generated method stub	
		}
	}
	//通过FutureTask包装类创建线程
	public class MyThreadClass{
	  //创建线程类
	  Callable<String>	callable = new ThreadD();
	  //创建未来执行的线程任务
	  FutureTask<String> futureTask = new FutureTask<String>(callable);
	  //创建线程池
	  ThreadPoolExecutor executor = ThreadUtil.newExecutor(5, 20);
	  //提交线程
	  executor.submit(futureTask);
	  //获取返回值
	  futureTask.get(30,TimeUnit.MINUTES);
	}
	
	public class ThreadD implements Callable<String>{
		@Override
		public String call() throws Exception {
			// TODO Auto-generated method stub
			String result= "返回值”
			return result;
		}
	}
}

3.synchronized 和 ReentrantLock的区别

相似点:
都是加锁的方式同步,而且都是阻塞式的同步;当一个线程或缺对象锁,进入了同步代码块,其他访问该同步代码块的线程都在外面等待,进行线程阻塞和唤醒的代价是比较高的。
区别:
1)、实现方式区别:
Synchronized是java语言的关键字,是语法层面的锁,需要JVM实现,
ReenTrantLock是JDK1.5以后提供的API层面的锁,需要lock()和unlock()配合try/catch实现
2)、避免死锁现象
Synchronized通过两个字节码指令标记当前锁的状态,如何锁不被释放,就会造成多线程的阻塞
ReenTrantLock是线程可中断的锁,如果等待一定时间无响应,获取锁的线程会自动释放,可以避免出现死锁现象
3)、公平锁
Synchronized是所有的线程同时争抢cpu时间片,会有指令重排,是非公平锁
ReenTrantLock是多线程同时访问一个锁对象时,会按照访问的先后顺序进行执行;默认是非公平锁,可通过参数true设置为公平所
4)、一个ReenTrantLock可以同时绑定多个对象

4.线程池

1).创建线程池方法

注:《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽 的风险。
Executors 返回线程池对象的弊端如下:
FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。 CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。

  1. 构造方法实现
    在这里插入图片描述
  2. 通过Executor 框架的工具类Executors来实现
    FixedThreadPool : 该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。
    当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在
    一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
    SingleThreadExecutor: 方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线
    程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
    *CachedThreadPool:*该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复 用。

对应Executors工具类中的方法如图所示:
在这里插入图片描述

2).常用线程池
3. newSingleThreadExecutor:创建一个单线程的线程池,此线程池保证所有任务的执行顺序按照 任务的提交顺序执行。
4. newFixedThreadPool:创建固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达 到线程池的大大小。
5. newCachedThreadPool:创建一个可缓存的线程池,此线程池不会对线程池大小做限制,线程池
大小完全依赖于操作系统(或者说JVM)能够创建的大线程大小。
6. newScheduledThreadPool:创建一个大小无限的线程池,此线程池支持定时以及周期性执行任 务的需求。
7. newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务 的需求

3)线程池的优点

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  2. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系
    统的稳定性,使用线程池可以进行统一的分配,调优和监控
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读