Java编程一道多线程问题实例代码

 更新时间:2018年02月07日 08:43:26   作者:eson_15  
这篇文章主要介绍了Java编程一道多线程问题实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

前面几篇博文基本上总结了一下java并发里的一些内容,这篇博文主要从一个问题入手,看看都能用到前面总结的哪些并发技术去解决。

题目描述:

模拟一个场景:处理16条日志记录,每条日志记录打印时间需要1秒,正常情况下如果将这16条记录去部打完需要16秒,现在为了提高效率,准备开启4个线程去打印,4秒钟打印完,实现这个demo。

  先来分析一下这个题目,关于这16条日志记录,我们可以在主线程中产生出来,这没用什么难度,关键是开启4个线程去执行,现在有两种思路:一种是日志的产生和打印日志的线程在逻辑上分开;一种是日志的产生和打印日志的线程在逻辑上不是分开的。这样说可能有点晦涩,下面我针对这两种思路,写个实现的demo就好理解了。

思路一

日志产生和日志打印在逻辑上是分开的。

  这相当于两条战线: 一条战线在不停的产生日志,另一个战线在不停的打印日志。很明显会想到阻塞队列的使用,产生日志不停的往阻塞队列中塞,打印日志不停的从阻塞队列中取,阻塞队列的大小可以自己设置,可以设置16个,也可以设置为1个,这都不影响执行。所以会用到BlockingQueue,下面看一下实现的demo:

public class Practice1 {
	public static void main(String[] args) {
		//定义一个阻塞队列,队列大小可以装16个信息
		BlockingQueue<String> queue = new ArrayBlockingQueue<String>(16);
		for (int i = 0; i < 4; i ++) {
			//开启四个线程去阻塞队列中取日志打印
			new Thread(new Runnable() {
				@Override
				        public void run() {
					while(true) {
						try {
							String log = queue.take();
							//取日志
							parseLog(log);
							//打印日志
						}
						catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
			).start();
		}
		System.out.println("begin:" + (System.currentTimeMillis()/1000));
		for (int i = 0; i < 16; i ++) {
			final String log = "" + (i+1);
			//表示一个日志
			try {
				queue.put(log);
				//将产生的日志塞到阻塞队列中去
			}
			catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	public static void parseLog(String log) {
		//打印日志的方法
		System.out.println(Thread.currentThread().getName() + "---"
		        + log + "---" + (System.currentTimeMillis()/1000));
		try {
			Thread.sleep(1000);
			//模拟打印一次日志需要1秒
		}
		catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

  这就好比一个系统正在运作,一边不停的产生日志,一边在不停的开启多个线程去打印日志信息,这个demo就写好了,运行结果就不贴了。

思路二

日志产生和日志打印在逻辑上不是分开的。

  这种思路就是,我产生日志的同时,你就给我打印出来,四个线程一起干!那么这种思路的话,就得用到线程池了,我一开始创建一个线程池,里面装了4个线程,然后产生日志的时候,我让这个线程池拿线程去执行它即可。demo如下:

public class Practice1 {
	public static void main(String[] args) {
		ExecutorService service = Executors.newFixedThreadPool(4);
		//创建一个线程池
		System.out.println("begin:" + (System.currentTimeMillis()/1000));
		for (int i = 0; i < 16; i ++) {
			final String log = "" + (i+1);
			//表示一个日志
			service.execute(new Runnable() {
				//拿一个线程去执行
				@Override
				        public void run() {
					parseLog(log);
				}
			}
			);
		}
		service.shutdown();
		//最后别忘了关掉线程池
	}
	public static void parseLog(String log) {
		System.out.println(Thread.currentThread().getName() + "---"
		        + log + "---" + (System.currentTimeMillis()/1000));
		try {
			Thread.sleep(1000);
			//模拟打印一次日志需要1秒
		}
		catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

关于这个问题,就总结到这吧,把这两种思路搞清楚一般就可以有效的解决了。

总结

以上就是本文关于Java编程一道多线程问题实例代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

相关文章

  • 详解SpringBoot如何删除引用jar包中的无用bean

    详解SpringBoot如何删除引用jar包中的无用bean

    为了赶速度和直接将之前多模块的maven项目中的部分模块,直接以jar包的形式引入到新项目中了,虽然省去了不少开发时间,导致项目臃肿,启动很慢。本文将用@ComponentScan注解去实现让项目只加载自己需要的bean,需要的可以参考一下
    2022-06-06
  • Spring中property-placeholder的使用与解析详解

    Spring中property-placeholder的使用与解析详解

    本篇文章主要介绍了Spring中property-placeholder的使用与解析详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • 一文详解Spring构造函数推断

    一文详解Spring构造函数推断

    这篇文章主要介绍了Spring构造函数推断自动注入及底层原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加
    2023-04-04
  • Mybatis如何通过接口实现sql执行原理解析

    Mybatis如何通过接口实现sql执行原理解析

    为了简化MyBatis的使用,MyBatis提供了接口方式自动化生成调用过程,可以大大简化MyBatis的开发,下面这篇文章主要给大家介绍了关于Mybatis如何通过接口实现sql执行原理解析的相关资料,需要的朋友可以参考下
    2023-01-01
  • Java详细讲解堆排序与时间复杂度的概念

    Java详细讲解堆排序与时间复杂度的概念

    本文主要介绍了java实现堆排序以及时间复杂度,堆排序这种排序算法是我们经常用到的,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Mybatis中resultMap标签和sql标签的设置方式

    Mybatis中resultMap标签和sql标签的设置方式

    这篇文章主要介绍了Mybatis中resultMap标签和sql标签的设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • java开发命名规范总结

    java开发命名规范总结

    包名的书写规范 (Package)推荐使用公司或机构的顶级域名为包名的前缀,目的是保证各公司/机构内所使用的包名的唯一性。包名全部为小写字母,且具有实际的区分意义
    2013-10-10
  • 从零开始学springboot整合feign跨服务调用的方法

    从零开始学springboot整合feign跨服务调用的方法

    这篇文章主要介绍了从零开始学springboot整合feign跨服务调用的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • 从内存方面解释Java中String与StringBuilder的性能差异

    从内存方面解释Java中String与StringBuilder的性能差异

    我们通常会发现使用StringBuffer或StringBuilder创建出来的字符串在拼接时回避String要来得快,尤其是StringBuilder,本文就从内存方面解释Java中String与StringBuilder的性能差异,需要的朋友可以参考下
    2016-05-05
  • 使用RestTemplate访问https实现SSL请求操作

    使用RestTemplate访问https实现SSL请求操作

    这篇文章主要介绍了使用RestTemplate访问https实现SSL请求操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10

最新评论