读写锁、线程池demo和概念
读写锁、线程池都是日常中及其常用的对象,大家需要掌握。
读写锁
ReadWriteLock 维护两个锁,一个读,一个写,读锁是并发的,写锁是独占的
/*
* 1. ReadWriteLock : 读写锁
*
* 写写/读写 需要“互斥”
* 读读 不需要互斥
*
*/
public class TestReadWriteLock {
public static void main(String[] args) {
ReadWriteLockDemo rw = new ReadWriteLockDemo();
new Thread(new Runnable() {
@Override
public void run() {
rw.set((int)(Math.random() * 101));
}
}, "Write:").start();
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
rw.get();
}
}).start();
}
}
}
class ReadWriteLockDemo{
private int number = 0;
private ReadWriteLock lock = new ReentrantReadWriteLock();
//读
public void get(){
lock.readLock().lock(); //上锁
try{
System.out.println(Thread.currentThread().getName() + " : " + number);
}finally{
lock.readLock().unlock(); //释放锁
}
}
//写
public void set(int number){
lock.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName());
this.number = number;
}finally{
lock.writeLock().unlock();
}
}
}
输出
Thread-1 : 0
Thread-2 : 0
Thread-7 : 0
Thread-6 : 0
Thread-9 : 0
Thread-10 : 0
Write:
Thread-0 : 31
Thread-3 : 31
Thread-4 : 31
Thread-13 : 31
Thread-14 : 31
Thread-18 : 31
Thread-21 : 31
Thread-25 : 31
Thread-29 : 31
Thread-33 : 31
Thread-34 : 31
Thread-42 : 31
Thread-37 : 31
Thread-45 : 31
Thread-49 : 31
Thread-50 : 31
Thread-53 : 31
Thread-57 : 31
Thread-58 : 31
Thread-61 : 31
Thread-62 : 31
Thread-65 : 31
Thread-66 : 31
Thread-69 : 31
Thread-73 : 31
Thread-74 : 31
Thread-77 : 31
Thread-78 : 31
Thread-82 : 31
Thread-86 : 31
Thread-89 : 31
Thread-90 : 31
Thread-94 : 31
Thread-98 : 31
Thread-8 : 31
Thread-11 : 31
Thread-15 : 31
Thread-5 : 31
Thread-16 : 31
Thread-85 : 31
Thread-70 : 31
Thread-97 : 31
Thread-54 : 31
Thread-46 : 31
Thread-93 : 31
Thread-12 : 31
Thread-30 : 31
Thread-38 : 31
Thread-22 : 31
Thread-96 : 31
Thread-41 : 31
Thread-91 : 31
Thread-81 : 31
Thread-83 : 31
Thread-92 : 31
Thread-17 : 31
Thread-76 : 31
Thread-67 : 31
Thread-87 : 31
Thread-19 : 31
Thread-95 : 31
Thread-99 : 31
Thread-26 : 31
Thread-23 : 31
Thread-71 : 31
Thread-24 : 31
Thread-20 : 31
Thread-27 : 31
Thread-28 : 31
Thread-31 : 31
Thread-32 : 31
Thread-36 : 31
Thread-35 : 31
Thread-40 : 31
Thread-39 : 31
Thread-47 : 31
Thread-44 : 31
Thread-43 : 31
Thread-48 : 31
Thread-51 : 31
Thread-52 : 31
Thread-55 : 31
Thread-56 : 31
Thread-68 : 31
Thread-59 : 31
Thread-72 : 31
Thread-60 : 31
Thread-84 : 31
Thread-63 : 31
Thread-64 : 31
Thread-88 : 31
Thread-79 : 31
Thread-75 : 31
Thread-80 : 31
线程池
一般我们测试的时候经常会新建多个线程来进行并发测试,这个时候我们是使用的单个的线程对象。
public class ThreadWithOutPool {
public static void main(String[] args) {
ThreadWithOutPoolOb threadWithOutPoolOb = new ThreadWithOutPoolOb();
new Thread(threadWithOutPoolOb).start();
new Thread(threadWithOutPoolOb).start();
}
}
class ThreadWithOutPoolOb implements Runnable{
private int i =0;
@Override
public void run() {
while (i<=100) {
System.out.println(Thread.currentThread().getName() + "t" +i++);
}
}
}

实际中,如果这么去编写代码,那么代码的效率会很低,而且会耗费资源。

之所以效率低,耗费资源,是因为每次线程使用时都需要创建线程,线程使用完成之后还需要销毁线程,因此,线程池就是来解决这个问题的。
线程池中会初始化一定数量的线程,在需要线程时,不需要创建,直接从池中拿出来用即可,用完了也不需要销毁,释放回到线程池中即可,因此极大地提升了效率和减小了开销。
核心接口–Executor

线程池的体系结构
* java.util.concurrent.Executor : 负责线程的使用与调度的根接口
* |--**ExecutorService 子接口: 线程池的主要接口
* |--ThreadPoolExecutor 线程池的实现类
* |--ScheduledExecutorService 子接口:负责线程的调度
* |--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService
*
* 工具类 : Executors
* ExecutorService newFixedThreadPool() : 创建固定大小的线程池
* ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
* ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
*
* ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。
Runable
public class ThreadWithOutPool {
public static void main(String[] args) {
ThreadWithOutPoolOb threadWithOutPoolOb = new ThreadWithOutPoolOb();
// new Thread(threadWithOutPoolOb).start();
// new Thread(threadWithOutPoolOb).start();
//1. 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
//2. 为线程池中的线程分配任务
for (int i = 0; i < 10; i++) {
pool.submit(threadWithOutPoolOb);
}
//3. 关闭线程池
pool.shutdown();
}
}
Callable
这里是拿了一个实际中的实例,在某一个系统中,需要对数据提供方提供的数据的规范性、准确性进行治理,我们这边定制了一套治理的程序,原本是按照一定规则将数据分区进行治理的处理,但是随着数据量的积累,治理的效率越来越低,因此考虑加大同时处理的线程数量,这里就需要对单任务的数据再次分割,实现多线程同时治理的效果,以提升效率,这里就是用到了线程池。
定义一个HandleCallable对象,用来封装处理逻辑,该对象实现了callable接口,可以分配给单个线程进行处理
public class HandleCallable<E> implements Callable<List<String>> {
private static Logger logger = LoggerFactory.getLogger(HandleCallable.class);
// 线程名称
private String threadName = "";
// 需要处理的数据
private List<E> data;
public HandleCallable(String threadName, List<E> data) {
this.threadName = threadName;
this.data = data;
}
@Override
public List<String> call() throws Exception {
// 该线程中所有数据处理返回结果
List<String> resultList = new ArrayList<>();
if (data != null && data.size() > 0) {
logger.info("线程:{},共处理:{}个数据,开始处理......", threadName, data.size());
// 循环处理每个数据
for (int i = 0; i < data.size(); i++) {
// 需要执行的数据
E e = data.get(i);
// 将数据执行结果加入到结果集中
resultList.add(e.toString()+"t"+threadName);
logger.info("线程:{},第{}个数据,处理完成", threadName, (i + 1));
}
logger.info("线程:{},共处理:{}个数据,处理完成......", threadName, data.size());
}
return resultList;
}
}
这里示例只是做了简单的字符串拼装和结果集返回,实际要比这个复杂的多,这里只是模拟。
刚才的测试类改为
public class ThreadWithOutPool {
public static void main(String[] args) {
ThreadWithOutPoolOb threadWithOutPoolOb = new ThreadWithOutPoolOb();
// new Thread(threadWithOutPoolOb).start();
// new Thread(threadWithOutPoolOb).start();
//1. 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
//模拟待处理数据
List<String> d = Arrays.asList("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
// 数据量大小
int length = d.size();
// 每个线程处理的数据个数
int taskCount = length / 5;
List<Future<List<String>>> r = new ArrayList<>();
for (int i = 0; i < 5; i++) {
// 每个线程任务数据list
List<String> subData = null;
if (i == (4)) {
subData = d.subList(i * taskCount, length);
} else {
subData = d.subList(i * taskCount, (i + 1) * taskCount);
}
HandleCallable<String> handleCallable = new HandleCallable<>(Thread.currentThread().getName(),d);
// 将线程加入到线程池
Future<List<String>> f = pool.submit(handleCallable);
r.add(f);
}
// //2. 为线程池中的线程分配任务
// for (int i = 0; i < 10; i++) {
// pool.submit(threadWithOutPoolOb);
// }
//
//3. 关闭线程池
pool.shutdown();
r.stream().forEach(x->{
try {
x.get().stream().forEach(System.out::println);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
}
}
线程调度
基于工具类进行线程的延迟调度。
public class TestScheduledTestDemo {
public static void main(String[] args) throws Exception {
//初始化调度线程池
ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 5; i++) {
Future<Integer> result = 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;
}
}, 1, TimeUnit.SECONDS);
System.out.println(result.get());
}
pool.shutdown();
}
}
原文始发于微信公众号(云户):读写锁、线程池demo和概念
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/25932.html