Java多线程总结

进程三大特征

独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的条件下,一个用户进程不可以直接访问其他进程的地址空间。

动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念。进程拥有自己的生命周期和各种不同的状态。

并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。

并发与并行:并行指在同一时刻,有多条指令在多个处理器上同时执行;并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

线程的创建和启动
  • 继承Thread类创建线程类
  1. 定义Thread类的子类,并重写run()方法,run方法称为线程执行体
  2. 创建Thread子类的实例,即创建了线程对象。
  3. 调用线程对象的start方法来启动线程。
  • 实现Runnable接口来创建线程类
  1. 定义Runnable接口的实现类,重写run()方法
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象。
  3. 调用线程对象的start()方法启动线程。
  • 使用Callable和Future创建线程
  1. 创建Callable接口的实现类并实现call()方法,call()方法将作为线程执行体且call()方法有返回值,再创建Callable实现类的实例。

  2. 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

  3. 使用FutureTask对象作为Thread对象的target创建并启动新线程

  4. 调用FutureTask对象的get()方法来获得子线程执行的返回值。

优缺点:

  • 实现Runnable、Callable接口的方式:

优点:实现Runnable、Callable接口的方式还可以继承其它类。

​ 多个线程共享同一个target对象,适合多个相同线程处理同一份资源。

缺点:编程复杂,需使用Thread.currentThread()方法来访问当前线程。

  • 继承Thread类的方式:

缺点:线程不能再继承其它类。

优点:边写简单,使用this便可获得当前线程,不用使用Thread.currentThread()方法。

线程的生命周期

在这里插入图片描述

控制线程
  • join线程:一个线程等待另一个线程完成的方法-join()方法,当在某个程序执行流中调用其他线程的join()方法,调用线程将被阻塞,知道被join()方法加入的线程执行完成。
  • 后台线程:有一种线程,它是在后台执行的,它的任务是为其他的线程提供服务,叫做后台线程。例如JVM垃圾回收线程。特征:如果所有的前台线程都死亡,后台线程会自动死亡。调用Thread对象的setDaemon(true)方法设置。
  • 改变线程优先级:每个线程默认的优先级都与创建它的父线程的优先级相同,Thread提供setPriority(int newPriority)、getPriority()方法来设置和返回线程的优先级。
  • 线程睡眠: 让当前正在执行的线程暂停一段时间,并进入阻塞状态,调用Thread.sleep()方法。Thread.yield():让当前正在执行的线程暂停,但不会阻塞该线程,只是将线程转入就绪状态。

sleep()方法与yield()区别:

  1. sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级,但yield()只会给优先级相同以及更高的线程执行机会。
  2. sleep()方法将线程转入阻塞状态,直到阻塞时间到才会转入就绪状态;而yield()不会将线程转入阻塞状态,他只是强制当前线程进入就绪状态。
  3. sleep()方法声明并抛出了InterruptedException,而yield()方法则没有声明抛出任何异常。
  4. sleep()方法比yield()方法有更好的可移植性。
线程同步
  • 同步代码块:线程开始执行同步代码块前,必须先获得同步监视器的锁定。
	synchronized (obj) {
		//同步代码块
	}
  • 同步方法:使用synchronized修饰的方法
  • 同步锁:ReadWriteLock,Lock,ReentrantLock, Java 8新增StampedLocked类
class{
		Private final ReentrantLock lock = new ReentrantLock();
		public void m(){
			//加锁
			lock.lock();
			try{
				//线程安全代码
			}finally{
				lock.unlock();//释放锁
			}
		}
	}
  • 死锁:当两个线程互相等待对方释放同步监视器时就会产生死锁。
线程通信
  • Object提供wait(),notify(),notifyAll()方法

      	wait():导致当前线程等待
    
      	notify():唤醒在此同步监视器上等待的单个线程。
    
      	notifyAll():唤醒在此同步监视器上等待的所有线程。
    
  • 使用Condition控制线程通信:使用Condition可以让那些已经得到Lock对象却无法继续执行的线程释放Lock对象。Condition类提供了三个方法:

      	await():导致当前线程等待
    
      	signal():选择唤醒其中一个线程。
    
      	signalAll():唤醒在此Lock对象上等待的所有线程。
    
  • 使用阻塞队列(BlockingQueue)控制线程通信:程序的两个线程通过交替向BlockingQueue中放入元素、取出元素,即可很好的控制线程的通信。

      put(E e):尝试把E元素放入队列中,如果队列满,阻塞该线程。
    
      take():尝试从队列头部取出元素,如果队列元素空,阻塞该线程。
    
线程组和未处理的异常

ThreadGroup可以对一批线程进行分类管理。Thread类提供了几个构造器来设置该新创建的线程属于哪个线程组。

		Thead(THreadGroup group,Runnable target)

		Thread(THreadGroup group,Runnable target, String name)

		Thread(THreadGroup group, String name)

线程组处理异常的默认流程:

  1. 如果该线程有父线程组,则调用父线程组的uncaughtException()方法来处理该异常。
  2. 如果该线程实例所属的线程类有默认的异常处理器(由setDefaultUncaughtExceptionHandler()方法设置的异常处理器),那么就调用该异常处理器来处理异常。
  3. 如果该异常对象是ThreadDeath的对象,则不做任何处理;否则,将异常跟踪栈的信息打印到System.err错误输出流,并结束该线程。
线程池

Executors工厂类产生线程池

  • newCachedThreadPool():创建一个具有缓存功能的线程池
  • newFixedThreadPool(int nThreads):创建一个具有固定数量的线程池。
  • newSingleThreadExecutor(int corePoolSize):创建一个只有单线程的线程池。
  • newScheduledThreadPool(int corePoolSize):创建一个具有固指定线程数的线程池,它可以在指定延迟后执行线程任务。
  • newSingleThreadScheduledExecutor():创建一个具有单个线程数的线程池,它可以在指定延迟后执行线程任务。
  • ExecutorService new WorkStealingPool(int parallelism):创建持有足够的线程的线程池来支持给定的并行级别。
  • ExecutorService newWorkStealingPool():上一个方法的简化版本。

使用线程池来执行线程任务的步骤:

  1. 调用Executors类的静态方法创建一个ExecutorService对象,该对象代表一个线程池。
  2. 创建Runnable实现类或Callable实现类的实例,作为线程执行任务。
  3. 调用ExecutorService对象的submit()方法来提交Runnable和Callable实例。
  4. 当不想提交任何任务时,调用ExecutorService对象的shutdown()方法来关闭线程池。

ForkJoinPool:支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合并成总的计算结果。

  • ForkJoinPool(int parallelism):创建一个包含parallelism个并行线程的ForkJoinPool。
  • ForkJoinPool():以Runtime.availableProcessors()方法的返回值作为parallelism参数来创建ForkJoinPool。
  • Java 8:ForkJoinPool commonPool():返回一个通用池。
  • int getCommonPoolParallelism():该方法返回通用池的并行级别。

创建了ForkJoinPool实例后,调用submit(ForkJoinTask task)或invoke(ForkJoinTask task)方法来执行指定任务了,ForkJoinTask代表一个可以并行、合并的任务。有两个抽象子类:RecursiveAction代表有返回值的任务和RecursiveTask代表没有返回值的任务。

在这里插入图片描述

线程相关类

ThreadLocal的功用就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。

  • T get():返回此线程局部变量中当前线程副本中的值。
  • void remove():删除此线程局部变量中当前线程的值。
  • voId set(T value):设置此线程局部变量中当前线程副本中的值。
线程安全的集合类

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值