导语
  如果想要深入的了解一个东西就需要不断的接近他,这样才能了解到其核心的东西。这个系列就来了解一下Java多线程。开始入坑吧!

  在入坑之前先来看一个例子!!

public class Test {public static void main(String[] args) {System.out.println(Thread.currentThread().getName());}
}

  上面代码创建了一个被称为是主线程的东西,这主线程执行的效果就是打印出当前线程的名字,效果如下

  控制台中输出的main其实就是这个线程的名字,需要声明的一点是控制台中输出的main与主函数main没有半点关系,只不过就是名称相同而已。

实现多线程的方式

  在很多的面试中面试官都在问实现多线程有几种方式,其实对于一个资深程序员来说,实现多线程的方式很多,就看你自己怎么定义多线程算是多线程,Java官方提供的方式就是继承Runnable接口。我们知道在Runnable接口里面有一个run()方法。但是真正使得线程运行的方法是start方法,start方法底层实现是调用了一个private native void start0();来创建一个线程运行run()方法中的内容。

@FunctionalInterface
public interface Runnable {/*** When an object implementing interface <code>Runnable</code> is used* to create a thread, starting the thread causes the object's* <code>run</code> method to be called in that separately executing* thread.* <p>* The general contract of the method <code>run</code> is that it may* take any action whatsoever.** @see     java.lang.Thread#run()*/public abstract void run();
}

继承Thread类

  下面就来介绍一下Runnable的官方实现Thread,在Java中我们知道要实现父类的功能可以通过继承接口或者父类的方式进行。这里Thread就是继承了Runnable接口的实现类,通过继承这个实现类就可以使用它里面的一些方法。
1、继承Thread类实现自定义的线程类

public class MyThread extends Thread {@Overridepublic void run() {super.run();System.out.println("MyThread");}
}

2、编写测试类

public class Run {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();System.out.println("运行结束!");}
}

  运行上面代码会发现两个输入结果的顺序是不一定的。也就是说运行多线程的时候代码的先后顺序与代码最后执行的结果顺序是无关的。线程是作为一个子任务存在的,CPU不确定什么时候调用,或者说是CPU时间片轮转是随机。
  这里我们来分析一个问题,既然start方法是作为启动子线程的方法,那么我们在同一个方法中重复的启动start方法是否可以创建多个线程呢?

public class Run {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();myThread.start();System.out.println("运行结束!");}
}

异常

Exception in thread "main" java.lang.IllegalThreadStateExceptionat java.lang.Thread.start(Thread.java:705)at com.thread.charp01.t1.mythread.Run.main(Run.java:13)
MyThread

  进入到start方法中看到如下内容!

 public synchronized void start() {/*** A zero status value corresponds to state "NEW".*/if (threadStatus != 0)throw new IllegalThreadStateException();group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}}}

  其中有一个threadStatus表示线程的状态,如果threadStatus为 0 则表示一个新的线程,否则就会调用IllegalThreadStateException异常进行抛出。

3、测试CPU调用的随机性

public class MyThread extends Thread {@Overridepublic void run() {super.run();try {for (int i = 0; i < 10; i++) {int time = (int) (Math.random()*1000);Thread.sleep(time);System.out.println("run= "+ Thread.currentThread().getName());}} catch (InterruptedException e) {e.printStackTrace();}}
}
public class Test {public static void main(String[] args) {try{MyThread thread = new MyThread();thread.setName("MyThread");thread.start();for (int i = 0; i < 10; i++) {int time = (int) (Math.random()*1000);Thread.sleep(time);System.out.println("main= "+ Thread.currentThread().getName());}} catch (InterruptedException e) {e.printStackTrace();}}
}

  在代码中,随机挂起了某些线程。执行结果如图所示,从结果中可以看出CPU执行那个线程并不是确定的。


  在返回对Start方法的分析,在Start方法中有个start0()的方法,它其实就是真正实现线程调用的方法,通过它将线程调用注入到一个类似于线程调度器中,然后等待CPU有时间的时候来进行调用然后执行run方法中的内容。这样就保证了整个的执行过程有中异步的感觉。但是如果线程直接调用的run方法则就是一个普通的方法调用。因为并没有一个新的线程被注入到线程调度器中,所以说还是在主线程中依次的去执行。

  下面就来演示一个异步调用的例子

public class MyThread extends Thread {private int i;public MyThread(int i){super();this.i = i;}@Overridepublic void run() {System.out.println(i);}
}
public class Test {public static void main(String[] args) {MyThread t1 = new MyThread(1);MyThread t2 = new MyThread(2);MyThread t3 = new MyThread(3);MyThread t4 = new MyThread(4);MyThread t5 = new MyThread(5);MyThread t6 = new MyThread(6);MyThread t7 = new MyThread(7);MyThread t8 = new MyThread(8);MyThread t9 = new MyThread(9);MyThread t10 = new MyThread(10);MyThread t11 = new MyThread(11);MyThread t12 = new MyThread(12);MyThread t13 = new MyThread(13);t1.start();t2.start();t3.start();t4.start();t5.start();t6.start();t7.start();t8.start();t9.start();t10.start();t11.start();t12.start();t13.start();}
}

执行结果如下

  从代码执行效果以及具体的逻辑来看,多线程的调用顺序与start方法调用的先后也是没有关系的。

  上面就是通过继承了Runnable接口类的子类Thread类来实现的效果,当然在Java中对于类继承只能是单继承,但是对于接口的继承却是多继承的,如果在某些情况下,我们不但想实现多线程的功能,还想实现其他接口的功能,那么不妨试试下面这种方式

继承Runnable接口

1、创建自定义类

public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("运行中");}
}

2、创建测试类

public class Run {public static void main(String[] args) {Runnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();System.out.println("运行结束");}
}

注意
  在使用Thread的时候我们可以直接调用Thread类中的start方法,但是如果实现了Runnable接口,只是表示它由一个run()方法准备执行,但是具体交给谁执行还需要通过Thread将执行线程加入到线程调度器中,这样才能使得CPU在合适的时间对其进行调度。

总结

  使用Thread类的方式开发多线程应用在程序设计上有一定的局限性,Java是单继承,不能支持多继承,所以使用Runnable可以打破这种局限性。

Java多线程编程系列-多线程基础相关推荐

  1. C#多线程编程系列(二)- 线程基础

    目录 C#多线程编程系列(二)- 线程基础 1.1 简介 1.2 创建线程 1.3 暂停线程 1.4 线程等待 1.5 终止线程 1.6 检测线程状态 1.7 线程优先级 1.8 前台线程和后台线程 ...

  2. C#多线程编程系列(五)- 使用任务并行库

    目录 1.1 简介 1.2 创建任务 1.3 使用任务执行基本的操作 1.4 组合任务 1.5 将APM模式转换为任务 1.6 将EAP模式转换为任务 1.7 实现取消选项 1.8 处理任务中的异常 ...

  3. C#多线程编程系列(一)- 简介

    目录 系列大纲 一.前言 二.目录结构 四.章节结构 五.相关链接 系列大纲# 目前只整理到第二章,线程同步,笔者后面会慢慢更新,争取能把这本书中精华的知识都分享出来. C#多线程编程系列(一)- 简 ...

  4. Java 网络编程系列之 NIO

    Java 网络编程系列之 NIO 第 1 章Java NIO 概述 1.1 IO 概述 IO 的操作方式 1.2 阻塞 IO (BIO) 1.3 非阻塞 IO(NIO) 1.4 异步非阻塞 IO(AI ...

  5. Java并发编程系列

    Java并发编程系列 2018-03-08 Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) ...

  6. (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹

    (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹 原文 (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹 (本系列文章由柠檬的(lc_mtt)原创,转载 ...

  7. Java 并发编程系列之带你了解多线程

    早期的计算机不包含操作系统,它们从头到尾执行一个程序,这个程序可以访问计算机中的所有资源.在这种情况下,每次都只能运行一个程序,对于昂贵的计算机资源来说是一种严重的浪费. 操作系统出现后,计算机可以运 ...

  8. 『图解Java并发编程系列』10张图告诉你Java并发多线程那些破事

    目录 线程安全问题 活跃性问题 性能问题 有态度的总结 头发很多的程序员:『师父,这个批量处理接口太慢了,有什么办法可以优化?』架构师:『试试使用多线程优化』第二天头发很多的程序员:『师父,我已经使用 ...

  9. Java并发编程进阶——多线程的安全与同步

    多线程的安全与同步 多线程的操作原则 多线程 AVO 原则 A:即 Atomic,原子性操作原则.对基本数据类型变量的读和写是保证原子性的,要么都成功,要么都失败,这些操作不可中断. V:即 vola ...

最新文章

  1. exa:一个 ls 命令的现代替代品
  2. edge新版 能够正则式_Python爬虫七 数据提取之正则
  3. 奇妙的Base64编码
  4. opencv生成随机图(随机彩图,随机灰图)
  5. sklearn模型评选择与评估
  6. Linux下的screen(远程协作的用法)
  7. “12306”的架构到底有多6?
  8. 信息系统项目管理师视频教程——10 信息系统项目管理基础
  9. 一周最新示例代码回顾 (4/9–4/15)
  10. Oracle账号及客户端下载
  11. PS学习总结一:入门版必备的基础功能
  12. 第三方支付机构是什么意思_什么是支付牌照 在哪查
  13. 巴菲特致股东的一封信:2004年
  14. word2010 2003公式编辑器 格式设置
  15. keep-alive的用法和作用
  16. python数字转换为大写中文_阿拉伯数字金额转中文大写 (python实现)
  17. Android 绘制电池图标
  18. xmlHttp.send(null)与xmlHttp.send…
  19. 微信小程序使用canvas制作拼图动画
  20. device的注册流程

热门文章

  1. enspar启动失败40_法式长棍面包,在家自己做,简单零失败,低糖无油不担心长胖...
  2. AOP五大通知注解详解
  3. php制作的ios端 跳转url,ThinkPHP 简易开发思路 MVC和URL跳转
  4. ethers.js-5-Utilities
  5. 2017年国内开源镜像站点汇总 1
  6. Java读写Excel之POI超入门(转)
  7. Bootstrap分页功能
  8. 聊聊四种Oracle数字取整函数
  9. FontAwesome-网站ui设计中一套非常棒的icon
  10. xp环境下 .net framework 3.5 安装过程过慢 原因浅析