线程的流程

线程的创建

有三种方法,重点掌握前两种:

  • 继承Thread类
  • 实现Runnable接口(推荐使用:避免单继承的局限性)
  • 实现Callable接口

根据java的思想,要少用继承,多用实现。

第一种:继承Thread类

继承Thread的类必需重写run方法,run方法即为线程体

当程序执行到start()时,不会等这句执行完,继续往下走,main方法与t中的run方法并发执行。

代码:

  1. package _20191203;
  2. /**
  3. * 创建线程的方法一:继承Thread
  4. * @author UID
  5. *
  6. */
  7. public class ThreadTest extends Thread{
  8. public static void main(String[] args) {
  9. ThreadTest t = new ThreadTest();
  10. t.start();//当程序执行到这里时,不会等这句执行完,继续往下走,main方法与t中的run方法并发执行
  11. for(int i = 0;i < 500;i++) {
  12. System.out.println("一边听歌");
  13. }
  14. }
  15. @Override
  16. public void run() { //必需重写run方法
  17. super.run();
  18. for(int i = 0;i < 800;i++) {
  19. System.out.println("一边敲代码");
  20. }
  21. }
  22. }

  

看看效果(结果有所截取):

  1. 一边听歌
  2. 一边听歌
  3. 一边听歌
  4. 一边听歌
  5. 一边听歌
  6. 一边听歌
  7. 一边听歌
  8. 一边听歌
  9. 一边听歌
  10. 一边敲代码
  11. 一边敲代码
  12. 一边敲代码
  13. 一边敲代码
  14. 一边敲代码
  15. 一边敲代码
  16. 一边敲代码
  17. 一边敲代码
  18. 一边听歌
  19. 一边听歌
  20. 一边听歌
  21. 一边听歌
  22. 一边听歌
  23. 一边听歌
  24. 一边听歌
  25. 一边听歌
  26. 一边敲代码
  27. 一边敲代码
  28. 一边敲代码
  29. 一边敲代码
  30. 一边敲代码
  31. 一边敲代码
  32. 一边敲代码
  33. 一边敲代码

  

第二种:实现Runnable接口

类直接实现Runnable接口,在类中写run方法,通过代理类Thread来调用它即可开启线程。

只使用一次的对象推荐使用匿名对象:

  1. new Thread(new xxx()).start();//xxx为实现了Runnable接口的类

  

代码:

  1. package _20191203;
  2. /**
  3. * 创建线程的方法一:继承Thread
  4. * @author UID
  5. *
  6. */
  7. public class ThreadTest implements Runnable{
  8. public static void main(String[] args) {
  9. new Thread(new ThreadTest()).start();//对象只使用一次时推荐使用匿名对象
  10. for(int i = 0;i < 200;i++) {
  11. System.out.println("一边听歌");
  12. }
  13. }
  14. @Override
  15. public void run() { //必需重写run方法
  16. for(int i = 0;i < 200;i++) {
  17. System.out.println("一边敲代码");
  18. }
  19. }
  20. }

  

第三种:实现Callable接口

这种方式,一般中小企业不会用到,它是一种高级方法,一般也要工作3到5年提升时才会学到,在这里只做了解,面试用。

流程:

需要做线程的类实现Callable接口,如:

一般要写上泛型。

  1. public class Test implements Callable<泛型>{}

  

实现Callable的类必需重写call方法,相当于run方法:

他需要有返回值。

  1. public <泛型> call() Throws Exception{}

  

然后在使用线程的方法中(如main方法):

主要有以下步骤

  1. //新建执行服务对象
    ExecutorService es = Executors.newFixedThreadPool(线程数量);
  2. //提交执行
    Future<泛型> result1 = es.submit(r1);//r1为实现了Callable接口的示例,有几个就写几行这行代码
  3. //获取结果
    泛型对应的类型 res1 = result1.get();如:Integer res1 = result1.get();
  4. //关闭服务
    es.shutdownNow();

  

龟兔晒跑的示例:

  1. package _20191203;
  2.  
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.Future;
  8.  
  9. /**
  10. * 多线程,龟兔赛跑
  11. * @author UID
  12. *
  13. */
  14. public class Race implements Callable<Integer>{
  15. private String winner;
  16. @Override
  17. public Integer call() throws Exception{
  18.  
  19. // TODO Auto-generated method stub
  20. for (int step = 1; step <= 100; step++) {
  21. System.out.println(Thread.currentThread().getName()+"--->"+step);
  22. if(winner != null) {
  23. break;
  24. }else if(step==100) {
  25. System.out.println("胜利者:"+Thread.currentThread().getName());
  26. return step;
  27. }
  28. }
  29. return null;
  30. }
  31.  
  32. public static void main(String[] args) {
  33. Race r1 = new Race();
  34. Race r2 = new Race();
  35.  
  36. //创建执行服务
  37. ExecutorService es = Executors.newFixedThreadPool(2);
  38. //提交执行
  39. Future<Integer> result1 = es.submit(r1);
  40. Future<Integer> result2 = es.submit(r2);
  41. //获取结果
  42. try {
  43. Integer res1 = result1.get();
  44. } catch (InterruptedException | ExecutionException e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. try {
  49. Integer res2 = result2.get();
  50. } catch (InterruptedException | ExecutionException e) {
  51. // TODO Auto-generated catch block
  52. e.printStackTrace();
  53. }
  54. //关闭服务
  55. es.shutdownNow();
  56.  
  57. }
  58. }

  

线程Thread类的构造方法与不安全线程

Thread(Runnable target,String name);

通过该构造方法创建线程时可以给线程起一个名字,这个名字可以使用Thread.currentThread().getName()来获取

例子:

抢票模拟,线程不安全型:

  1. package _20191203;
  2. /**
  3. * 模拟抢票:此代码线程不安群
  4. * @author UID
  5. *
  6. */
  7. public class Thread12306 implements Runnable{
  8. private int source = 100;
  9. public void run() {
  10. while(source>0) {
  11. source--;
  12. System.out.println(Thread.currentThread().getName()+" 抢到了票!还剩:"+source);
  13. try {
  14. Thread.sleep(100);
  15. } catch (InterruptedException e) {
  16. // TODO Auto-generated catch block
  17. e.printStackTrace();
  18. }
  19. }
  20.  
  21. }
  22.  
  23. public static void main(String[] args) {
  24. Thread t1 = new Thread(new Thread12306(),"线程1");
  25. Thread t2 = new Thread(new Thread12306(),"线程2");
  26. Thread t3 = new Thread(new Thread12306(),"线程3");
  27. t1.start();
  28. t2.start();
  29. t3.start();
  30.  
  31. }
  32. }

  

运行结果,线程不安全的后果:

27 多线程(一)——创建进程的三种方法、线程锁(同步synchornized与lock)的更多相关文章

  1. Linux启动新进程的三种方法

    程序中,我们有时需要启动一个新的进程,来完成其他的工作.下面介绍了三种实现方法,以及这三种方法之间的区别. 1.system函数-调用shell进程,开启新进程system函数,是通过启动shell进 ...

  2. cocos2dx中创建动画的三种方法

    1.最最原始的方法,先创建动画帧,再创建动画打包(animation),再创建动画(animate) 第一步: 创建动画帧:CCSpriteFrame,依赖于原始的资源图片(xx.png,xx.jpg ...

  3. Linux中创建Daemon进程的三种方法

    什么是daemon进程? Unix/Linux中的daemon进程类似于Windows中的后台服务进程,一直在后台运行运行,例如http服务进程nginx,ssh服务进程sshd等.注意,其英文拼写为 ...

  4. MySQL创建用户的三种方法 (并授权)转

    前言:MySQL创建用户的方法分成三种:INSERT USER表的方法.CREATE USER的方法.GRANT的方法. 一.账号名称的构成方式 账号的组成方式:用户名+主机(所以可以出现重复的用户名 ...

  5. ORM 创建manytomay的三种方法 反向查询 和一些 双下方法版学员管理系统3

    老师信息管理   三种创建多对对外键的方式常用第二种和第三种 思考 三种方式创建多对多外键方式及其优缺点. 外键的查询和使用 1外键的创建: 在数据库表中的表现形式 如何连表查询和使用 表里边:  s ...

  6. MySQL创建用户的三种方法

    前言:MySQL创建用户的方法分成三种:INSERT USER表的方法.CREATE USER的方法.GRANT的方法. 一.账号名称的构成方式 账号的组成方式:用户名+主机(所以可以出现重复的用户名 ...

  7. Jenkins 批量创建任务的三种方法

    最近,要搭建多套测试环境,需要把 Jenkins 中 dev 视图下的所有任务批量复制到 sit 等视图下. 说明 Jenkins 任务名称规则为:[测试环境标识]-[工程名称],如:dev-daod ...

  8. [HTML/CSS]创建新元素的三种方法

    第一种:通过text/HTML var txt1="<h1>Text.</h1>"; 第二种:通过jQuery var txt2=$("<h ...

  9. Java创建数组的三种方法

    ■ 第一种: int[] arr=new int[6]; arr[0] = 1; arr[1] = 2 arr[2] = 3; arr[3] = 4; arr[4] = 5; arr[5] = 6; ...

随机推荐

  1. 查看.NET应用程序中的异常(下)

    为什么要使用内存转储进行调试? 在两种主要情况下,您可能需要使用内存转储进行调试.第一种情况是应用程序有一个未处理的异常并崩溃,而您只有一个内存转储.第二种情况是,在生产环境中出现异常或特定行为,并且 ...

  2. Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

    Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because ...

  3. 洛谷 P2850 [USACO06DEC]虫洞Wormholes 题解

    P2850 [USACO06DEC]虫洞Wormholes 题目描述 While exploring his many farms, Farmer John has discovered a numb ...

  4. 查全率(Recall),查准率(Precision),灵敏性(Sensitivity),特异性(Specificity),F1,PR曲线,ROC,AUC的应用场景

    之前介绍了这么多分类模型的性能评价指标(<分类模型的性能评价指标(Classification Model Performance Evaluation Metric)>),那么到底应该选 ...

  5. 59、Spark Streaming与Spark SQL结合使用之top3热门商品实时统计案例

    一.top3热门商品实时统计案例 1.概述 Spark Streaming最强大的地方在于,可以与Spark Core.Spark SQL整合使用,之前已经通过transform.foreachRDD ...

  6. C语言博客作业00--我的第一篇博客

    1.你对网络专业或者计算机专业了解是怎样? 起初 起初对于我来说,计算机专业毕业后就相当于程序员,或者去开发一些游戏,软件等等,而学得特别优秀的可能会成为黑客,就像电影电视剧里演得那样,这是我一开始的 ...

  7. 数据仓库DW、ODS、DM概念及其区别

    整体结构 在具体分析数据仓库之前先看下一下数据中心的整体架构以及数据流向   数据中心整体架构.png DB 是现有的数据来源,可以为mysql.SQLserver.文件日志等,为数据仓库提供数据来源 ...

  8. 刷题记录:[De1ctf] shell shell shell

    目录 刷题记录:[De1ctf] shell shell shell 一.知识点 1.源码泄露 2.正则表达式不完善导致sql注入 3.soapclient反序列化->ssrf 4.扫描内网 5 ...

  9. git 全量同步分支

    当前分支是maser分支,我想将stable分支上的代码完全覆盖brush分支,首先切换到brush分支. git reset --hard origin/stable 执行上面的命令后brush分支 ...

  10. Redis配置讲解及实战

    前言 Redis是一个开源的内存k-v数据库,同时也可用作缓存,消息队列.支持多种数据类型,如字符串,列表,字典,集合,有序集合. 演示环境 $ uname -a Darwin Darwin Kern ...