线程

什么是线程:

 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源

表面上是多线程其实是cpu快速轮流切执行

多线程(并行和并发)

  1. 并行:两个任务同事进行,就是甲任务执行的同时,乙任务也在执行(需要多核)
  2. 并发:两个任务都请求运行,而处理器只能接受一个任务,就把这两个任务安排轮流执行。由于时间间隔很短,使人感觉两个任务都在运行

多线程(java程序运行的原理)

java命令会启动jvm等于启动了一个应用程序(一个进程)。该进程会自动启动“主线程”,主线程去调用main方法

启动jvm是单线程的么?

不是,是多线程的。至少会启动垃圾回收线程和主线程

可通过下面代码来验证,主线程和垃圾回收线程在互相抢占资源

public class TestThread {

    public static void main(String[] args) {
//4.创建Thread的子类对象
MyThread myThread = new MyThread(); //5.启动线程,注意这里使用的是start而不是run方法
myThread.start(); for (int i = 0; i < 10000; i ++) {
System.out.println("This is main thread");
}
} } //1.继承Thread
class MyThread extends Thread{ //2.重写run方法
@Override
public void run() {
super.run();
//3.线程方法中要执行的代码,可以根据自己的需求填写
for(int i = 0 ; i < 10000 ; i ++ ) {
System.out.println("This is MyThread thread ");
}
}
}

java中如何创建多线程

(1)继承Thread类并调用start方法

Thread实现了Runnable接口

要实现多线程,就要成为thread的子类,并且重写run方法。注意在启动线程的时候,调用的不是run方法而是start方法。如果调用run方法,那么相当于一个普通方法并不会开启线程

public class Thread implements Runnable
public class TestThread {

    public static void main(String[] args) {
MyThread myThread = new MyThread();
//注意这里使用的是start而不是run方法
myThread.start(); for (int i = 0; i < 10000; i ++) {
System.out.println("This is main thread");
}
} } class MyThread extends Thread{ @Override
public void run() {
super.run(); for(int i = 0 ; i < 10000 ; i ++ ) {
System.out.println("This is MyThread thread ");
}
}
}

(2)实现runnable接口,并重写run方法

Runnable中只有一个方法run(),而线程启动方法存在与Thread中,
那么我们在最终启动线程的时候,势必是要通过Thread的子类对象去启动线程的
public class TestRunnable {

    public static void main(String[] args) {
//4.创建Thread的子类对象
Runnable myRunnable = new MyRunnable(); //5.启动线程,创建Thread并把runnable的子类作为构造参数
new Thread(myRunnable).start(); for (int i = 0; i < 10000; i ++) {
System.out.println("This is main thread");
}
} }
//1.实现runnable接口
class MyRunnable implements Runnable { //2.重写run方法
@Override
public void run() {
//3.线程方法中要执行的代码,可以根据自己的需求填写
for(int i = 0 ; i < 10000 ; i ++ ) {
System.out.println("This is MyRunnable thread ");
}
}
}

实现Callable接口

要实现线程,除了继承thread和runnable,还可以实现Callable接口。Callable接口提供了一个call()方法可以作为线程执行体,和run()的作用一样。但call()方法比run()方法多了返回值,call()方法可以声明抛出的异常。那么我们如何开启Callable线程呢?因为Callable接口不是Runnable接口的子接口,所以Callable对象不能作为Thread的构造参数。Java提供了另一个接口RunnableFuture接口,该接口实现了Runnable, Future接口,意味着我们可以把RunnableFuture的实现对象作为构造参数船体给Thread。RunnableFuture接口提供FutureTask实现类,我们可以通过调用FutureTask的get()方法,来获取call()的返回值

  1. 实现Callable接口
  2. 重写call方法,相当于thread中的run方法。不同的是call方法允许有返回值
  3. 把Callable实现类对象作为构造参数传入FutureTask创建FutureTask对象。
  4. 把FutureTask对象作为构造参数传入Thread,并开启线程
public class CallableDemo {

    public static void main(String[] args) {
//3.把Callable实现类对象作为构造参数传入FutureTask创建FutureTask对象。
FutureTask<UUID> futureTask = new FutureTask<UUID>(new MyCallable());
//4.把FutureTask对象作为构造参数传入Thread,并开启线程
new Thread(futureTask).start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
} //1. 实现**Callable**接口
class MyCallable implements Callable<UUID> { //2.重写**call**方法,相当于thread中的run方法。不同的是call方法允许有返回值
@Override
public UUID call() throws Exception {
//生成随机数
return UUID.randomUUID();
}
}

继承Thread,实现Runnable和Callable的区别

从源码的实现上

继承Thread

子类重写Thread中的run()方法,调用start()方法,jvm会自动调用子类的run()

实现Runnable

new Thread(myRunnable)在Thread的构造函数中参入runnable的引用,然后传给thread的成员变量target。在Thread run()方法中判断了如果target不为空,就调用子类的run方法

    public void run() {
if (this.target != null) {
this.target.run();
}

实现Callable接口

实现Callable接口重写Call()方法,并且可以提供线程返回值,也可以抛出异常。最终通过Runnable的子接口RunnableFuture的实现类FutureTask,传给Thread的成员变量target。

从使用上和拓展上

继承Thread

  1. 优点:直接调用thread中的start()方法,十分简单
  2. 缺点:java只支持单继承,如果子类继承了thread无法再继承其他类

实现Runnable

  1. 优点:java可以多实现
  2. 缺点:代码书写比较复杂,不能直接调用start()

实现Callable

  1. 优点:java可以多实现,可以抛出异常,可以有返回值
  2. 缺点:代码书写比较复杂

java中多线程 - 如何创建多线程的更多相关文章

  1. Java中使用CountDownLatch进行多线程同步

    CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantL ...

  2. 第九节:详细讲解Java中的泛型,多线程,网络编程

    前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...

  3. Java中String对象创建机制详解()

    一String 使用 private final char value来实现字符串存储 二Java中String的创建方法四种 三在深入了解String创建机制之前要先了解一个重要概念常量池Const ...

  4. Java中两种实现多线程方式的对比分析

    本文转载自:http://www.linuxidc.com/Linux/2013-12/93690.htm#0-tsina-1-14812-397232819ff9a47a7b7e80a40613cf ...

  5. Java分享笔记:创建多线程 & 线程同步机制

    [1] 创建多线程的两种方式 1.1 通过继承Thread类创建多线程 1.定义Thread类的子类,重写run()方法,在run()方法体中编写子线程要执行的功能. 2.创建子线程的实例对象,相当于 ...

  6. java中的线程创建和使用

    Java中实现多线程有两种途径:继承Thread类或者实现Runnable接口.Runnable是接口,建议用接口的方式生成线程,因为接口可以实现多继承,况且Runnable只有一个run方法,很适合 ...

  7. Java中如何动态创建接口的实现

    有很多应用场景,用到了接口动态实现,下面举几个典型的应用: 1.mybatis / jpa 等orm框架,可以在接口上加注解进行开发,不需要编写实现类,运行时动态产生实现. 2.dubbo等分布式服务 ...

  8. Java中泛型数组创建总结

    在java中,可以声明一个泛型数组,不能通过直接通过T[] tarr=new T[10]的方式来创建数组,最简单的方式便是通过Array.newInstance(Classtype,int size) ...

  9. Java中数组的创建

    Java中数组的使用 1.普通数组变量的定义: //数组 //1.数组是Java中很重要的一部分,今天对数组进行了大致的了解,Java中的数组和C中数组还是有一定的区别的 //以下是总结的几种方法 p ...

随机推荐

  1. MySql错误处理--错误代码和消息

      附录B:错误代码和消息 目录 B.1. 服务器错误代码和消息 B.2. 客户端错误代码和消息 本章列出了当你用任何主机语言调用MySQL时可能出现的错误.首先列出了服务器错误消息.其次列出了客户端 ...

  2. CentOS7 64位下MySQL安装与配置(YUM)

    安装环境:腾讯云CentOS7 64位安装MySQL5.7 1.配置YUM源 在MySQL官网中下载YUM源rpm安装包:http://dev.mysql.com/downloads/repo/yum ...

  3. hadoop之mapreduce详解(优化篇)

    一.概述 优化前我们需要知道hadoop适合干什么活,适合什么场景,在工作中,我们要知道业务是怎样的,能才结合平台资源达到最有优化.除了这些我们当然还要知道mapreduce的执行过程,比如从文件的读 ...

  4. ajax跨域问题以及解决方案

    转:https://blog.csdn.net/csdn_ds/article/category/6937392/3 在工作中,大家应该都遇到过ajax跨域问题,浏览器的错误如下: XMLHttpRe ...

  5. vue使用readAsDataURL实现选择图片文件后预览

    vue实现选择图片文件后预览 利用h5的api可以实现选择文件并实现预览 readAsDataURL 方法会读取指定的 Blob 或 File 对象.读取操作完成的时候,readyState 会变成已 ...

  6. Java基础学习笔记(二) - 面向对象基础

    面向对象 一.面向对象概述 面向对象思想就是在计算机程序设计过程中,参照现实事物,将事物的属性特征.行为特征抽象出来,描述成计算机时间的设计思想.面向对象思想区别于面向过程思想,强调的是通过调用对象的 ...

  7. SpringBootSecurity学习(15)前后端分离版之 OAuth2.0简单示例

    OAuth2.0 OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者.客户端来申请资源,资源所有者同意以后,资源服务器可以向客户端颁发令牌.客户端通过令牌,去请求数据.也就是说, ...

  8. 前端深入之css篇|link和@import到底有什么区别?

    写在前面 在真正的前端开发中,我们很少去写行内样式和内嵌样式,通常都是去引用外部样式. 而在我们学习之初的外部样式表都是用link引入的,但是当后来我们学习的逐渐深入,发现@import也可以引入样式 ...

  9. Bumblebee服务网关之统一请求验证

    对于微服务网关来说,统一请求验证是一个比较重要和常用的功能,通过网关验证后台服务就无须关注请求验证:对于多语言平台的服务而言制定验证方式和变更验证配置都是一件比较繁琐和工作量大的事情.Bumblebe ...

  10. Transactional事务提交后触发异步方法

    一.问题复现 1.场景 2个service方法, 方法A中调用方法B. 方法A 是核心业务方法,涉及多张表数据变更,为了保持数据一致,用spring事务注解:@Transactional(rollba ...