多线程基础篇(1)——初试线程
1.线程概念
1.1 线程与进程
一个CPU在同一时间只能处理一个进程(程序),而一个进程包含至少一个或多个线程,操作系统会对每个进程分配相应的系统资源,如cpu,内存等,而进程中的所有线程将会共享这些资源。
进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
1.2 并行与并发
1.并行:真正意义上的同时运行
2.并发:只是通过CPU的时间片分配算法来循环执行所有任务,cpu不断地切换执行线程,造成同时运行 的错觉。
1.3 线程状态
1)新建状态(New):新创建了一个线程对象。
2)就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的进程除CPU之外,其它的运行所需资源都已全部获得。
3)运行状态(Running):就绪状态的线程获取了CPU时间片,执行程序代码。
4)阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
5)终止:线程run方法中执行到return,或发生了一个未处理(try-catch)的异常时,则会发生线程终止。
6)等待状态:表示当前线程进入等待状态,并且需要其他线程进行通知或中断。
7)超时等待状态:表示当前线程进入等待状态,并且需要其他线程进行通知或中断,也可以在一定时间后自动返回
注:等待状态,超时等待状态实际上也算阻塞状态。
2.简单线程代码实现
2.1 通过继承Thread类创建
继承Thread,重写run方法并在run方法中添加任务逻辑代码,即可创建一个线程。
public class Demo2{ public static void main(String[] args) { for(int i=0;i<=20;i++){ test t=new test(i); t.start(); System.out.println("main thread"+i); } } } class test extends Thread{ int i; public test(int i){ this.i=i; } //重写run方法 @Override public void run(){ System.out.println("new thread"+i); } }
2.2 实现Runnable接口
public class Demo3 { public static void main(String[] args) { //实现Runnable 接口 Runnable r=new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; //将Runnable对象作为参数传入Thread构造方法 Thread t=new Thread(r); t.start(); } }
2.3 实现Callable接口
这是一种特殊的方法,因为其可以获得返回值或者抛出异常,而Runnable与Thread皆不可以,但Callable线程任务对象只能交由线程池来执行。其返回值用Future对象来接收。
public class Demo5 { public static void main(String[] args) throws Exception { Callable<String> c=new Callable<String>() { @Override public String call() throws Exception { // TODO Auto-generated method stub return "callable"; } }; ExecutorService executors=Executors.newFixedThreadPool(5); Future<String> f=executors.submit(c); System.out.println(f.get()); } }
使用Runnable,Callable接口实现对比继承Thread类的优点:
1)实现了线程对象与线程任务的解耦
2)避免了类的单继承问题,获得了更好的扩展性
2.4 线程池的简单使用
与数据库连接池类似,我们通过一个线程池对象(执行器)来动态的生成管理线程对象,只需传入线程任务对象(Runnable,Callable),则线程池对象将自动的创建或者复用线程对象。
public class Demo4 { public static void main(String[] args) { //创建线程池对象,通过工厂类来创建线程池 ExecutorService executors=Executors.newFixedThreadPool(5);//创建一个可重用的固定线程数的线程池 Executors.newCachedThreadPool();//创建一个根据需要可随时创建新线程的线程池,当已经创建的线程中有可用的时便重用 Executors.newSingleThreadExecutor();//创建一个使用单个线程的线程池,并以无界队列方式运行 //调用方法提交线程任务并执行 Runnable task=new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; executors.execute(task); } }
注:Runnable与Callable对象的提交执行方式不同,Runnable对象调用execute方法,而Callable对象调用submit方法。
欢迎各位指出错误以及不足,谢谢

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
微信支付中退款踩坑记录
首先附上微信支付的开发者文档 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_16&index=11 其实这里所说的踩坑记录,无非就是微信在开发者文档上的写不太明确,也没有比较官方的demo,在此列出一个可行的demo,供大家下载使用。 主要问题就是在这几步解密上 微信的解密算法 首先是base64解码的工具类 base64Utils 这个工具类都是比较简单的,大部分的框架都会封装这种类似的工具类,这里自己做简单封装 然后是md5工具类,这个就不往外放了,网上多的是,现成的也多的是 主要坑人的地方是第三条。。。 解密参数设置 AES解密方法 上面写明了用AES-256-ECB-PKCS7Padding,但是你把下面的ALGORITHM_MODE_PADDING参数换成AES/ECB/PKCS7Padding,发现报了这么个异常 java.security.NoSuchAlgorithmException: Cannot find any provider supporting DES/ECB/PKCS7P...
- 下一篇
Python爬虫的两套解析方法和四种爬虫实现
对于大多数朋友而言,爬虫绝对是学习python的最好的起手和入门方式。因为爬虫思维模式固定,编程模式也相对简单,一般在细节处理上积累一些经验都可以成功入门。本文想针对某一网页对python基础爬虫的两大解析库(BeautifulSoup和lxml)和几种信息提取实现方法进行分析,以开python爬虫之初见。 基础爬虫的固定模式 笔者这里所谈的基础爬虫,指的是不需要处理像异步加载、验证码、代理等高阶爬虫技术的爬虫方法。一般而言,基础爬虫的两大请求库urllib和requests中requests通常为大多数人所钟爱,当然urllib也功能齐全。两大解析库BeautifulSoup因其强大的HTML文档解析功能而备受青睐,另一款解析库lxml在搭配xpath表达式的基础上也效率提高。就基础爬虫来说,两大请求库和两大解析库的组合方式可以依个
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Hadoop3单机部署,实现最简伪集群