JUC多线程

2023-11-16

1. 读写锁 ReadWriteLock

  • 读读之间不需要互斥 ,读写 写写之间需要互斥
  • 通过readWriteLock.readLock().lock();//上锁 readWriteLock.readLock().unlock();//解锁 readWriteLock.writeLock().lock();//上锁 readWriteLock.writeLock().lock();//解锁
  • ReadWriteLock也是一个接口,具体实现:ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    具体代码实现:
/*
 * 1.ReadWriterLock:读写锁
 * 写写/读写--要进行“互斥”  读读不需要“互斥”
 */
public class TestReadWriterLock {
	public static void main(String[] args) {
		ReadWriterLockDemo readWriterLockDemo=new ReadWriterLockDemo();
		new Thread(new Runnable() {
			@Override
			public void run() {
				readWriterLockDemo.set((int)(Math.random()*101));
			}
		},"Write").start();
		for (int i = 0; i < 100; i++) {
			new Thread(new Runnable() {		
				@Override
				public void run() {
					readWriterLockDemo.get();
				}
			}).start();
		}
	}
}
class ReadWriterLockDemo{
	private int number=0;
	private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
	//读
	public void get() {
		readWriteLock.readLock().lock();//上锁
		try {
			System.out.println(Thread.currentThread().getName()+" :"+number);
		} finally {
			readWriteLock.readLock().unlock();
		}
	}
	//写
	public void set(int number) {
		readWriteLock.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName());
			this.number=number;
		} finally {
			readWriteLock.writeLock().unlock();
		}
	}
}

2. 线程八锁

  • 1.当两个普通同步的锁,标准打印 —>one two
/*
 * 判断 打印的是"one" or "two"
 */
public class TestThread8Monitor {
	public static void main(String[] args) {
		//1.当两个普通同步的锁,标准打印 --->one two
		Number number=new Number();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getOne();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getTwo();
			}
		}).start();
	}
}
class Number {
	public synchronized void getOne() {
		System.out.println("one");
	}
	public synchronized void getTwo() {
		System.out.println("two");
	}
}
  • 2.当给getOne()加上Thread.sleep()—>one two
	public synchronized void getOne() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("one");
	}
  • 3.当增加一个普通放入方法 getThree()时,会打印–>three one two
    public void getThree() { System.out.println("three"); }
  • 4.两个普通的同步方法 两个number对象 ---->two one
public static void main(String[] args) {
		//1.当两个普通同步的锁,标准打印 --->one two
		Number number=new Number();
		Number number2=new Number();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getOne();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number2.getTwo();
			}
		}).start();
//		new Thread(new Runnable() {
//			@Override
//			public void run() {
//				number.getThree();
//			}
//		}).start();
	}
}
class Number {
	public synchronized void getOne() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("one");
	}
	public synchronized void getTwo() {
		System.out.println("two");
	}
	public  void getThree() {
		System.out.println("three");
	}
}
  • 总结
  • 判断 打印的是"one" or “two”
    *1.当两个普通同步的锁synchronized,标准打印 —>one two
    *2.当给getOne()加上Thread.sleep()—>one two
    *3.当增加一个普通放入方法 getThree()时,会打印–>three one two
    *4.两个普通的同步方法 两个number对象 ---->two one
    *5.修改getOne()为static同步方法 一个number对象–>two one
    *6.修改getOne(),getTwo()为static同步方法 ,一个number对象 -->one two
    *7. getOne()静态同步,getTwo()非静态同步方法,两个number对象 —>two one
    *8. getOne()静态同步,getTwo()静态同步方法,两个number对象 —> one two
/*
 * 判断 打印的是"one" or "two"
 *1.当两个普通同步的锁synchronized,标准打印 --->one two
 *2.当给getOne()加上Thread.sleep()--->one two
 *3.当增加一个普通放入方法 getThree()时,会打印-->three  one two
 *4.两个普通的同步方法 两个number对象 ---->two one
 *5.修改getOne()为static同步方法  一个number对象-->two one
 *6.修改getOne(),getTwo()为static同步方法 ,一个number对象 -->one two
 *7. getOne()静态同步,getTwo()非静态同步方法,两个number对象 --->two one
 *8. getOne()静态同步,getTwo()静态同步方法,两个number对象 ---> one two
 *
 *线程八锁的关键:
 *		1)非静态方法的锁为this,静态方法的锁为对应的class实例
 *		2)某个时刻内,只能有一个线程持有锁,不管有几个方法
 */
public class TestThread8Monitor {
	public static void main(String[] args) {
		//1.当两个普通同步的锁,标准打印 --->one two
		Number number=new Number();
		Number number2=new Number();
		new Thread(new Runnable() {
			@Override
			public void run() {
				number.getOne();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				//number.getTwo();
				number2.getTwo();
			}
		}).start();
//		new Thread(new Runnable() {
//			@Override
//			public void run() {
//				number.getThree();
//			}
//		}).start();
	}
}
class Number {
	public static synchronized void getOne() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
		}
		System.out.println("one");
	}
	public static synchronized void getTwo() {
		System.out.println("two");
	}
	public  void getThree() {
		System.out.println("three");
	}
}

3.线程池

  • 使用线程池的原因:
		ThreadPoolDemo threadPoolDemo=new ThreadPoolDemo();
		new Thread(threadPoolDemo).start();//启动线程
		//每次要使用线程是 必须呀创建一个线程 并启动,每次用过完 就会销毁 如果每次都创建 销毁就会很浪费资源

在这里插入图片描述
使用1:

	
		 //1.创建线程池 
		ExecutorService poolExecutorService = Executors.newFixedThreadPool(5);// 创建5个线程的线程池
		ThreadPoolDemo threadPoolDemo = new ThreadPoolDemo(); // 2.为线程池中的线程分配任务
		for (int i = 0; i < 10; i++) {
			poolExecutorService.submit(threadPoolDemo);
		} // 3.关闭线程池
		poolExecutorService.shutdown();// 等待当前线程完成就关闭线程 //
		poolExecutorService.shutdownNow();// 立即关闭

使用2:

		ExecutorService poolExecutorService = Executors.newFixedThreadPool(5);
		List<Future<Integer>> list = new ArrayList<Future<Integer>>();
		for (int i = 0; i <= 10; i++) {
			Future<Integer> futureTask = poolExecutorService.submit(new Callable<Integer>() {
				@Override
				public Integer call() throws Exception {
					int sum = 0;
					for (int i = 0; i <= 100; i++) {
						sum = sum + i;
					}
					return sum;
				}
			});
			list.add(futureTask);
		}
		for (Future<Integer> future : list) {
			System.out.println(future.get());
		}
		poolExecutorService.shutdown();
	}

4.线程池调度

  • ScheduledTreahExecutor newScheduledThreadPool():创建固定大小的线程,可以延迟或定时执行任务
  • Executors.newScheduledThreadPool(5);
mport java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/*
 * 1.线程池:提供了一个线程队列,队列中的保存着所有等待状态的线程。避免了创建与销毁的额外开销,提高了响应的速度
 * 2.线程池的体系结构:
 * 	java.util.concurrent.Executor:负责线程的使用与调用的跟接口
 *    |-- **ExecutorService 子接口:线程池的主要接口
 *       |-- ThreadPoolExecutor :线程池实现类
 *       |-- ScheduledExecutorService :子接口  负责线程的调度
 *       	|-- ScheduledTreahExecutor:继承了ThreadPoolExecutor,实现了ScheduledExecutorService
 * 3.工具类
 *ExecutorService  newFixedThreadPool():创建固定大小的连接池
 * ExecutorService newCachedThreadPool():缓存线程池,线程池的大小不固定,可以根据需求自动更改数量
 * ExecutorService newSingleThreadExecutor():线程池中只有一个线程池
 * 
 * ScheduledTreahExecutor newScheduledThreadPool():创建固定大小的线程,可以延迟或定时执行任务

 */

public class TestScheduledThreadPool {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ScheduledExecutorService pool=Executors.newScheduledThreadPool(5);
		for(int i=0;i<10;i++) {
			Future<Integer> res=pool.schedule(new Callable<Integer>() {
				@Override
				public Integer call() throws Exception {
					int num=new Random().nextInt(100);
					System.out.println(Thread.currentThread().getName()+" :"+num);
					return num;
				}
			}, 2, TimeUnit.SECONDS);//延迟3秒
			System.out.println(res.get());
		}
		pool.shutdown();
	}
}

分支合并框架 ForkJoinPool

  • JDK7出来的
  • Fork/join框架:在必要的情况下,将一个大的任务,进行拆分(fork)成若干个小的任务(拆到不可拆分时),再将一个个小的任务的运算结果进行join汇总
  • 多个线程同时跟多个小任务进行运算
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;

import org.junit.Test;

public class TestForkJoinPool {
	public static void main(String[] args) {
		//因为拆分时需要时间的 
		Instant start=Instant.now();
		ForkJoinPool pool=new ForkJoinPool();//有它的支持才能正常运行
		ForkJoinTask<Long> forkJoinTask=new ForkJoinSumCalculate(0,1000000000L);
		Long sum=pool.invoke(forkJoinTask);//执行
		System.out.println(sum);
		Instant end=Instant.now();
		System.out.println("消耗的时间:"+Duration.between(start, end).toMillis());//
	}
	
	@Test
	public void test1() {//普通
		Instant start=Instant.now();
		long sum=0L;
		for(long i=0L;i<=1000000000L;i++) {
			sum+=i;
		}
		System.out.println(sum);
		Instant end=Instant.now();//获取现在的时间
		System.out.println("消耗的时间:"+Duration.between(start, end).toMillis());//		
	}
	
	@Test
	public void test2() {利用JDK8新特性来实现 拆分合并,对他进行了改进
		Instant start=Instant.now();
		long sum=LongStream.rangeClosed(0L, 1000000000L)
				.parallel()//并行流
				.reduce(0L, Long::sum);
		System.out.println(sum);
		Instant end=Instant.now();//获取现在的时间
		System.out.println("消耗的时间:"+Duration.between(start, end).toMillis());//		
	}
}
//以递归的方式 把大任务拆分成一个个的小任务
//RecursiveAction:没有返回值
//RecursiveTask<T>:有返回值
class ForkJoinSumCalculate extends RecursiveTask<Long>{
	private static final long serialVersionUID = 1L;
	private long start;
	
	private long end;
	private static final long THURSHOLD=10000L;//临界值 就是不能再拆分 thurshold
	
	public ForkJoinSumCalculate(long start,long end) {
		this.start=start;
		this.end=end;
	}
	public ForkJoinSumCalculate() {
	}
	@Override
	protected Long compute() {
	//拆分运算
		long len=end-start;
		if(len<=THURSHOLD) {//如果为临界值
			long sum=0L;
			for(long i=start;i<=end;i++) {//如果到达临界值 就直接运算总和
				sum+=i;
			}
			return sum;
		}else {//如果还能拆 就直接拆
			long middle=(start+end)/2;
			ForkJoinSumCalculate leftCalculate=new ForkJoinSumCalculate(start, middle);
			leftCalculate.fork();//进行拆分 同时压入线程队列
			ForkJoinSumCalculate rightCalculate=new ForkJoinSumCalculate(middle, end);
			rightCalculate.fork();//进行拆分	
			return leftCalculate.join()+rightCalculate.join();//把结果进行合并操作
		}	
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JUC多线程 的相关文章

  • ThreadPoolExecutor线程池解析与BlockingQueue的三种实现

    目的 主要介绍ThreadPoolExecutor的用法 和较浅显的认识 场景的使用方案等等 比较忙碌 如果有错误还请大家指出 ThreadPoolExecutor介绍 ThreadPoolExecutor的完整构造方法的签名如下 Thre
  • C# Task异步编程

    Task任务用法 Task用的是线程池 线程池的线程数量的有上限的 这个可以通过ThreadPool修改 我们经常会用到task run new task 和task factory startnew方法来创建任务 Task Factory
  • 如何正确使用线程池

    具体请参考原创 Java线程池实现原理及其在美团业务中的实践 Java 线程池及参数动态调节详解 一 为何要使用线程池 降低资源消耗 线程的创建和销毁会造成一定的时间和空间上的消耗 线程池可以让我们重复利用已创建的线程 提高响应速度 线程池
  • Qt 中开启线程的五种方式

    作者 billy 版权声明 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 简介 在开发过程中 使用线程是经常会遇到的场景 本篇文章就来整理一下 Qt 中使用线程的五种方式 方便后期回顾 前面两种比较简单 一笔带过了 主
  • 线程池的主要处理流程及常用方法

    线程池的主要处理流程及常用方法 更多优秀文章 请扫码关注个人微信公众号或搜索 程序猿小杨 添加 一 主要处理流程 当调用线程池execute 方法添加一个任务时 threadPoolExecutor execute 具体代码如下 priva
  • 线程池运行原理

    核心参数 corePollSize 核心线程池的大小 maximumPollSize 线程池能创建线程的最大个数 keepAliveTime 空闲线程存活时间 unit 时间单位 为keepAliveTime指定时间单位 workQuequ
  • 并发编程 :Concurrent 用户指南 ( 下 )

    并发编程 Concurrent 用户指南 下 2017 09 04 ImportNew 来源 高广超 www jianshu com p 8cb5d816cb69 锁 Lock java util concurrent locks Lock
  • 【Java线程】线程池的创建

    线程池装配类 线程池优雅停机控制 Configuration public class FeedBackExecutorConfig implements ApplicationListener
  • Java线程池execute()方法源码解析

    先看作者给出的注释来理解线程池到底有什么作用 Thread pools address two different problems they usually provide improved performance when execut
  • Java 线程池

    今天准备详细介绍java并发包下的Executor 以及Java提供了很多灵活的且极其方便的线程池的创建 嗯 那就慢慢说 大家肯定都学过Socket JavaSe的时候写聊天程序 游戏的服务器 以及Android程序自己需要提供服务器的 都
  • ScheduledThreadPoolExecutor 及 ThreadPoolExecutor的基本使用及说明

    关于作者 CSDN内容合伙人 技术专家 从零开始做日活千万级APP 专注于分享各领域原创系列文章 擅长java后端 移动开发 人工智能等 希望大家多多支持 目录 一 导读 二 概览 2 1 为什么不推荐使用Executors去创建线程池 三
  • python实现线程池

    参照c 的线程池 使用python的threading库实现线程池 import threading import time 线程池的任务 包含一个可调用对象和一个参数数组 class ThreadTask object def init
  • C++11的半同步半异步线程池

    C 11的半同步半异步线程池 简介 同步队列 Take函数 Add函数 Stop函数 SyncQueue完整代码 线程池 主函数测试 简介 半同步半异步线程池用的比较多 实现也比较简单 其中同步层包括同步服务层和排队层 指的是将接收的任务排
  • Java 数据库连接池、线程池和对象池总结

    一 Java数据库连接池总结 数据库连接池的实现及原理 内容摘要 对于一个复杂的数据库应用 频繁的建立 关闭连接 会极大的减低系统的性能 因为对于连接的使用成了系统性能的瓶颈 有一个很著名的设计模式 资源池 该模式正是为了解决资源频繁分配
  • springboot线程池ThreadPoolTaskExecutor使用

    https mp weixin qq com s 3DRBX9Wb OA NIfPXZjcw 前言 程池ThreadPoolExecutor 而用的是Spring Boot项目 可以用Spring提供的对ThreadPoolExecutor
  • Linux---多线程、线程池

    多线程 线程概念 线程就是进程中的一条执行流 负责代码的执行调度 在linux下线程执行流是通过pcb实现的 一个进程中可以有多个pcb 这些pcb共享进程中的大部分资源 所以线程被称为一个轻量级进程 Notes 进程是系统进行资源分配的基
  • 线程连接池

    第一种 Executors newCacheThreadPool 可缓存线程池 先查看池中有没有以前建立的线程 如果有 就直接使用 如果没有 就建一个新的线程加入池中 缓存型池子通常用于执行一些生存期很短的异步型任务 package tes
  • java使用线程池批量插入mysql数据

    首先我们使用最原始的for循环插入数据 for int i 0 i lt 100000000 i service add new LongTest setStatus 1 setName NumberUtil getPwdRandom 5
  • 并发编程----4.java并发包中线程池的原理研究

    并发编程 4 java并发包中线程池的原理研究 java并发包中线程池ThreadPoolExecutor的原理研究 线程池的优点 线程的复用 减少线程创建和销毁带来的消耗 提供了一种资源限制和线程管理的手段 比如限制线程的个数和动态新增线
  • 在一个线程池中,通常无法直接访问和检查单个线程的状态,因为线程池是由多个线程组成的,并且线程的执行情况可能会动态变化

    在一个线程池中 通常无法直接访问和检查单个线程的状态 因为线程池是由多个线程组成的 并且线程的执行情况可能会动态变化 然而 你可以通过一些方法来间接地查看线程是否在运行 一种常见的方法是为线程池中的每个线程设置一个标志或状态变量 用于表示线

随机推荐

  • el-table + setup语法糖 + 列表变化后滚动条置顶

    el table setup语法糖 列表变化后滚动条置顶 由于需要做一个el table 然后再更新地图同时将滚动条滚至最上 但是网上很多资料都是使用this refs 底部 this nextTick gt this refs table
  • SSM框架---springMVC

    目录 一 概述 分层思想 二 工作原理 1 导入jar包 2 创建启动类 三 处理请求参数 3 1 get方式 3 2 post方式 3 3 restful方式 推荐 四 处理get 请求的参数 五 处理post请求的参数 六 处理rest
  • ACM学习计划

    看完人家的博客 发现任重道远 一位高手对我的建议 一般要做到50行以内的程序不用调试 100行以内的二分钟内调试成功 acm主要是考算法的 主要时间是花在思考算法上 不是花在写程序与debug上 下面给个计划你练练 第一阶段 练经典常用算法
  • PHP的bcadd()函数用法

    求和后保留X位小数的函数 一般用于价格累加 查询出来的价格即使是浮点型 但是运用 后会变成整型 若需求需要保留小数位 则需要用到这个函数 bcadd 被加数 加数 保留几位小数 bcadd 1 3 2 4 00
  • 华为OD机试真题-最长密码【2023.Q1】

    题目描述 小王在进行游戏大闯关 有一个关卡需要输入一个密码才能通过 密码获得的条件如下 在一个密码本中 每一页都有一个由26个小写字母组成的若干位密码 每一页的密码不同 需要从这个密码本中寻找这样一个最长的密码 从它的末尾开始依次去掉一位得
  • 从零开始学前端(一)

    1 在桌面空白的地方 点击右键新建一个文本文档 2 双击或者右键打开刚刚新建的文件 3 将下面的代码复制到刚刚打开的txt文件中 h1 大家好 我是一只羊 这是我的第一个网页 h1 p Hello world p 4 点击文件 点击另存为
  • Mysql模糊查询like效率,以及更高效的写法

    原文来自 https www cnblogs com chaobest p 6737901 html 在使用msyql进行模糊查询的时候 很自然的会用到like语句 通常情况下 在数据量小的时候 不容易看出查询的效率 但在数据量达到百万级
  • Linux的学习步骤

    linux 基本操作命令 linux 各种配置 环境变量配置 网络配置 服务配置 linux 环境下搭建各种开发环境 Linux 写基本的shell脚本 对linux进行维护 Linux 安全设置 防止攻击 保障服务器的正常运行 能对系统尽
  • 飞腾CPU虚拟化相关代码分析(三)

    飞腾CPU虚拟化相关代码分析 三 函数set cpu boot mode flag 基本描述 根据CPU启动模式 来设置 boot cpu mode全局数组变量 函数输入输出描述 输入 寄存器w0 函数el2 setup的输出 寄存器w0
  • 树形dp(例题)

    树的最长路径带权值 树的直径可能时红色的边 从上图可以看出 每次要两个变量存放以u为根 最长路径d1 和次长路径d2 那么整个树的最长路径就有可能是d1 d2 我们每次要返回以u为根的贯穿试的最长路径 给他的父节点判断使用如下图 inclu
  • 如何求矩阵的逆矩阵

    如何求矩阵的逆矩阵 叮叮当当sunny 博客园 求逆矩阵最有效的方法是初等变换法 虽然还有别的方法 如果要求方阵 AA 的逆矩阵 标准的做法是 将矩阵 AA 与单位矩阵 II 排成一个新的矩阵 AI AI 将此新矩阵 AI AI 做初等行变
  • 埋点是什么?有什么作用?前端如何埋点?

    一 什么是埋点 埋点 tracking 是指在应用程序中插入代码或工具来记录某些事件的行为和属性 例如用户在应用中的点击 浏览 购买 注册等操作行为 这些数据可以被用来分析用户行为 优化产品功能 改进用户体验等 通过埋点 开发人员可以采集用
  • /Library/Developer/CommandLineTools/usr/bin/python3 :NO module named pytest解决

    报错场景 已经用pip3 install pytest 成功下载pytest 结果运行python3 m pytest xxx py还是报错 Library Developer CommandLineTools usr bin python
  • *python解决狼羊菜过河问题

    python解决狼羊菜过河问题 A岸有菜 羊 狼 农夫农夫必须将他们都送到B岸每次只能送一个 在保证他们不会被吃的前提下 完成任务 并得出步骤 代码 A 狼 1 羊 1 菜 1 B 狼 0 羊 0 菜 0 size len A count
  • 没有与这些操作数匹配的`“>>“`运算符错误;

    报错信息 没有与这些操作数匹配的 gt gt 运算符错误 网上查询大多是少了头文件
  • python反混淆javascript代码

    JavaScript代码一般都是可见的 一些关键的加密算法写在JS里其实很不安全 代码混淆能将Js进行压缩 使之变成不易读的代码 如下图所示 当然这难不倒我们 网上有很多js反混淆的工具 作者推荐使用jsbeautifier 因为最近项目用
  • CSDN上传付费资源需要创作者等级Lv4,我的升级之路,本文持续更新,欢迎各位分享自己的升级经验

    首先来看看官方的要求 创作者等级Lv4 实名认证 原力等级 5 目前惟一满足的实名认证 创作者等级升级官方说明 计分标准 计分规则 分值 说明 资源量 每上传1个资源 审核通过 5分 若自行或被平台删除及下架则扣除对应分数 分数实时更新 阅
  • 【React】react-router-dom

    文章目录 1 路由器组件 lt HashRouter gt lt BrowserRouter gt 2 路由 2 1 lt Route gt 2 1 1 lt Route element gt 2 1 2 lt Route path gt
  • 函数内的ajax同步请求导致遮罩层失效、或者导致loading正在加载提示失效问题

    功能需求 编写点击按钮 弹出loading遮罩层提示正在加载中 同时查询后台信息 拼接数据后渲染到列表时 为了保障渲染时 列表中的数据已经拼接完成 所以在for循环中使用同步ajax进行请求 在success方法中进行拼接 function
  • JUC多线程

    JUC多线程 1 读写锁 ReadWriteLock 2 线程八锁 3 线程池 4 线程池调度 分支合并框架 ForkJoinPool 1 读写锁 ReadWriteLock 读读之间不需要互斥 读写 写写之间需要互斥 通过readWrit