这个都是入门和一般的常规知识,大佬轻喷

①、继承Thread类

②、实现Runnable接口(常用,优点多)

③、实现Callable接口

实现Runnable和Callable接口的类只能当作一个可以在线程中运行的target,不是真正意义上的线程,最后还需要Thread来调用。

在Runnable中,实现类的run方法作为线程的执行体,实际的线程对象依然是Thread实例。Callable接口与Runnable相比,Callable可以有返回值,返回值通过FutureTask进行封装,Callable还可以向上抛出异常。

————————————————

一、继承Tread类

Thread类实现了Runnable接口,在java.long包下。

创建执行线程方法一:将类继承Thread类,重写Thread类的run方法。接下来就可以分配并启动该子类的实例。

具体步骤:

①、继承Thread类

②、重写run方法

③、将执行的代码写在run方法中

④、创建Thread类的子类对象

⑤、使用start方法开启线程。

注意:调用run方法不能开启多线程。

只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。

如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。

一个线程不能多次开启是非法的

下面就按照上述继承Tread类实现多线程的例子

package com.bjut.Multithreading;

public class ThreadTest {

public static void main(String[] args) {

//4,创建Thread类的子类对象

MyThread mt = new MyThread();

//5,使用start方法开启线程

mt.start();

for (int i = 0; i < 5; i++) {

System.out.println("main方法:" + i);

}

}

}

//1.继承Thread类

class  MyThread extends  Thread{

//2,重写run方法

@Override

public void run(){

//3,将执行的代码写在run方法中

for (int i = 0; i <5; i++) {

System.out.println("MyThread的run方法:"+i);

}

}

}

只有调用了start方法才是启动了多线程,输出就是固定为mainrun(因为run方法中有休眠的时刻,多线程main语句就已经执行了)

方法二:实现Runnable接口

声明实现Runnable接口的类,实现Runnable接口中仅有的run方法,然后分配实例对象,在创建Thread时作为一个参数来传递并启动。具体步骤如下

①、定义类实现Runnable接口

②、在该类中实现Runnable接口中的run()方法

③、线程中具体要执行的东西写在run()方法中

④、创建自定义Runnable实现类对象

⑤、创建Thread类的对象,并在该对象中传入该实现Runnable接口的对象作参数

⑥、Thread类的对象调用start()方法开启新线程,其内部会自动的调用run方法

package com.bjut.Multithreading;

public class RunnableTest {

public static void main(String[] args) {

MyRunnable mr = new MyRunnable(); //④、创建自己定义的Runnable实现类的对象

Thread thread = new Thread(mr); //⑤、创建Thread类的对象,并将自定义Runnable实现类的对象作为参数传递给Thread的构造函数

thread.start(); //⑥使用thread类的start方法开启线程。

for (int i = 0; i < 5; i++) {

System.out.println("main方法中:" + i);

}

}

}

//①、定义一个Runnable实现类

class MyRunnable implements Runnable {

//②、实现Runnable接口中的抽象方法

@Override

public void run() {

//③、在run方法中写入要使用多线程的具体方法

for (int i = 0; i < 5; i++) {

System.out.println("MyRunnable的方法中" + i);

}

}

}

使用匿名内部类的方式来实现继承Thread类和实现Runnable接口的方法来实现多线程

package com.bjut.Multithreading;

public class AnonymousThread {

public static void main(String[] args) {

// 继承Thread类实现多线程

new Thread() {

@Override

public void run() {

for (int i = 0; i < 5; i++) {

System.out.println("继承Thread类实现多线程"+Thread.currentThread().getName() + "--" + i);

}

}

}.start();

// 实现Runnable接口实现多线程

new Thread(new Runnable() {

@Override

public void run() {

for (int i = 0; i < 5; i++) {

System.out.println("实现Runnable接口实现多线程"+Thread.currentThread().getName() + "--" + i);

}

}

}) {

}.start();

}

}

多线程的两种实现方式(实现Runnable接口、和继承Thread类)的区别

源码中的区别

继承Thread类方式:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()方法(Java虚拟机自动完成)

实现Runnable方式:构造函数中传入了Runnable的引用,传给了Thread类中的成员变量,start()调用了run()方法时的内部判断成员变量Runnable的引用是否为空,若不为空,编译时看的是Runnable的run(),运行时执行的是具体实现类中的run()

优缺点:

继承Thread类方式

好处:可以直接使用Thread类中的方法,代码简单

弊端:同样也是面向对象中的继承的缺点:如果该具体类已经有了其他的父类,那么就不能多重继承Thread类,就不能使用这种方法。此时面向接口编程的优势脱颖而出。

实现Runnable接口方式

好处:即继承的弊端:即使自己定义的线程类有了其他父类也可以实现该Runnable接口。Java中的接口是多实现的,继承是单继承,比较有局限性。

弊端:不能直接使用Thread类中的方法,需要先把Runnable具体实现类对象传递给Thread类并获取到线程对象后,才能得到Thread类的方法,代码相对复杂

方式三:实现Callable接口

步骤:

创建实体类,实现Callable接口

实现接口中的call()方法

利用 ExecutorService线程池对象 的 <T> Future<T> submit(Callable<T> task()方法提交该Callable接口的线程任务。

实现callable接口,提交给ExecutorService返回值是异步执行的。

该方式的优缺点:

优点:

有返回值

可以抛出异常

缺点:

代码较复杂,需要利用线程池

/**

* @ Author zhangsf

* @CreateTime 2019/9/21 - 8:15 AM

*/

package com.bjut.Multithreading;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.FutureTask;

/**

* Callable是一个接口,里面只有一个方法:call,此方法有返回值。

*/

public class CallableDemo implements Callable {

@Override

public String call() throws Exception {    //可以有返回值

return Thread.currentThread().getName();

}

public static void main(String[] args) throws InterruptedException, ExecutionException {

CallableDemo cd=new CallableDemo();

FutureTask ft=new FutureTask(cd);

FutureTask ft1=new FutureTask(cd);

Thread td=new Thread(ft);

Thread td1=new Thread(ft1);

td.setName("张三");

td1.setName("李四");

td.start();

td1.start();

System.out.println(ft.get());    //通过get方法获取返回值

System.out.println(ft1.get());

}

}

使用线程池的方式:

//1、corePoolSize 线程池核心线程大小

//2、maximumPoolSize 线程池最大线程数量

//3、keepAliveTime 空闲线程存活时间

//4、unit 空闲线程存活时间单位

//5.workQueue 工作队列

/*①ArrayBlockingQueue

基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。

当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,

等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene

基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,

当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,

因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

③SynchronousQuene

一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,

不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,

则执行拒绝策略。

④PriorityBlockingQueue

具有优先级的无界阻塞队列,优先级通过参数Comparator实现。*/

//6.threadFactory 线程工厂

//7.handler 拒绝策略

/*①CallerRunsPolicy

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

②AbortPolicy

该策略下,直接丢弃任务,并抛出RejectedExecutionException异常

③DiscardPolicy

该策略下,直接丢弃任务,什么都不做。

④DiscardOldestPolicy

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列*/

ExecutorService executorService1 = new ThreadPoolExecutor(2,5,

        5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(3),new ThreadPoolExecutor.AbortPolicy());

创建规定大小的线程:

ExecutorService executorService = Executors.newFixedThreadPool(5);
单个线程

ExecutorService executorService1 = Executors.newSingleThreadExecutor();
可以扩容额线程

ExecutorService executorService2 = Executors.newCachedThreadPool();

在实际的开发中我们是不会使用java给我们提供的线程池的

就是因为这个: BlockingQueue<Runnable> workQueue

无界阻塞队列:

他的值是int的最大值: this(Integer.MAX_VALUE);这样一来很容易就oom了.

这个不是我瞎说的哦,java的底层代码就是这样实现的

ThreadPoolExecutor

一般就用的是这个创建线程池啦,7大参数,上面都有说明哦,

希望对你们有帮助

面试题---->线程的入门,读完可以应付一般的面试(管理员不要移除我的随笔啊)的更多相关文章

  1. C#中的线程(一)入门

    文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 作者 Joseph Albahari,  翻译 Swanky Wu 中文翻译作者把原文放在了& ...

  2. C#中的线程(一)入门 转

    文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 作者 Joseph Albahari,  翻译 Swanky Wu 中文翻译作者把原文放在了& ...

  3. JAVA 线程池入门事例

    线程池这个概念已经深入人心了,今天就是通过几个入门事例,学习一下线程池在JAVA中的应用. 一.大小固定的线程池——Executors.newFixedThreadPool() 下面咱们明确两个类: ...

  4. C#中的线程(一)入门 转载

    文章系参考转载,英文原文网址请参考:http://www.albahari.com/threading/ 转载:http://www.cnblogs.com/miniwiki/archive/2010 ...

  5. java-多线程的入门_进阶总结

    多线程 概述图 1.概述 进程:正在执行中的程序,其实时应用程序在内存中运行的那片空间. 线程:进程中的一个执行单元,负责进程中的程序的运行,一个进程中至少要有一个线程. (进程可以理解为是一个QQ程 ...

  6. Java线程池入门

    序 为什么要用线程池?什么情况下才会用到线程池? 并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 因此 ...

  7. Java面试题-线程安全

    1. 什么叫线程安全?servlet是线程安全吗?       答:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他 ...

  8. C#中的线程(上)-入门 分类: C# 线程 2015-03-09 10:56 53人阅读 评论(0) 收藏

    1.     概述与概念 C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行.一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为"主线 ...

  9. Java线程池入门必备

    线程池 一. 线程池的简介 1.什么是线程池?   最早期的工作线程处理任务的模型.一个任务的到来,会伴随着线程的创建,当处理完任务后,线程会被销毁,资源回收.这种一个任务一个线程一系列创建销毁的模式 ...

随机推荐

  1. Java8的新特性--并行流与串行流

    目录 写在前面 Fork/Join框架 Fork/Join框架与传统线程池的区别 传统的线程池 Fork/Join框架 Fork/Join框架的使用 Java8中的并行流 写在前面 我们都知道,在开发 ...

  2. TextRank算法及生产文本摘要方法介绍

    TextRank 算法是一种用于文本的基于图的排序算法,其基本思想来源于谷歌的 PageRank算法,通过把文本分割成若干组成单元(句子),构建节点连接图,用句子之间的相似度作为边的权重,通过循环迭代 ...

  3. Day2:Windows常用快捷键与基本的Dos命令

    Windows常用快捷键 必须掌握: Ctrl+C:复制 Ctrl+V:粘贴 Ctrl+Z:撤销 Ctrl+S:保存 Win键+R:运行(run) alt+F4:关闭窗口/页面 Ctrl+A:全选 C ...

  4. C语言数组寻址

    C语言数组 数组的定义 数组是用来存放数据类型相同且逻辑意义相同的数据 数组的大小 数组的大小不能是变量,必须是常量或者常量表达式,常量表达式由编译器编译时自动求值. 也可以不指定数组大小,但必须对数 ...

  5. 灵魂拷问!浏览器输入「xxxxhub」的背后.....

    Hey guys 各位读者姥爷们大家好,这里是程序员 cxuan 计算机网络连载系列的第 13 篇文章. 到现在为止,我们算是把应用层.运输层.网络层和数据链路层都介绍完了,那么现在是时候把这些内容都 ...

  6. python基础之流程控制(2)

    今天将是基础篇的最后一篇,咱们来补上最后一个内容,流程控制for循环 For 循环 一.为什么有for循环? for循环能做的事情,while循环全都可以实现,但是在某些情境下,for循环相对于whi ...

  7. Android Studio 如何在TextView中设置图标并按需调整图标大小

    •任务 相信大家对这张图片都不陌生,没错,就是 QQ动态 向我们展示的界面. 如何实现呢? •添加文字并放入图标 新建一个 Activity,取名为 QQ,Android Studio 自动为我们生成 ...

  8. .NET 开源配置组件 AgileConfig 初体验

    介绍 在微服务大行其道的今天,系统会被拆分成多个模块,作为单独的服务运行,同时为了集中化管理,我们还需要日志中心,配置中心等,很多开发人员可能更熟悉 ApolloConfig,这个组件功能也很完善,d ...

  9. web编辑工具 - Brackets - 强大免费的开源跨平台Web前端开发工具IDE

      简单使用可以参考: https://blog.csdn.net/melon19931226/article/details/68066971/ https://www.iplaysoft.com/ ...

  10. 【WPF】将控件事件中的参数,传递到ViewModel中

    在MVVM模式下,在通常使用命令(Command)绑定的方式的时候 ,使用的是 CommandParameter 属性进行参数的传递. 但是很多时候,有一些事件我们需要使用其中的一些事件里面的参数,以 ...