好好学习,天天向上




本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航

前言

俗话说得好“一人拾柴火不旺,众人拾柴火焰高”,一个人的力量毕竟是有限的,想要把一件事情做好,免不了需要一帮人齐心协力。同样的道理,一个复杂程序里面不会只有一个线程在工作,必然是很多个线程在一起工作。那么,这篇文章作为Java并发学习系列的第一篇,就来聊一聊Java并发的基础知识:进程和线程。

进程和线程概念

进程

什么是进程呢?进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。简单的说进程就是一个正在运行的程序,打开任务管理器,可以看到有很多的进程。

比如写文章用的Typora,写程序用的IDEA等,这些都是进程。

线程

那么线程又是什么呢?线程是操作系统能够进行运算调度的最小单位。每个进程里面都包含了一个或多个线程,比如我正在运行的IDEA里面就包含了58个线程。

举个栗子:平时大家应该会用视频软件看视频吧,那么播放视频,下载视频,上传视频,弹幕功能等,这些都是一个个单独线程,这些线程之间可以互相协作,也可以互不干扰的运行。

线程和CPU之间的关系

线程作为操作系统的最小调度单位,同一时间只能运行在一个CPU核心上。现在的操作系统都是分时操作系统,一个线程不会一直占用一个CPU核心,而是等待操作系统的任务调度器分配CPU时间片给一个线程,这个线程才能运行,否则只能在一边等着。就像网吧一样,每台机子就相当于一个CPU核心,上网的人就是线程。每个人不管时间多少都是时间限制的,下机后就给另外的人上,没有机子的人就在一边等着别人下机。不过网吧上网时间是由你自行决定的,而线程的运行时间是操作系统分配的。不过一个CPU时间片特别短,所以你感觉所有的线程都是一起运行的,其实是存在线程切换的。

并行和并发

既然要学习Java并发,那么首先得知道并行和并发的概念吧。

并行

  • 并行(parallel)是同一时间动手做(doing)多件事情的能力

举个栗子:中午了,大家都在食堂打饭,现在有两个窗口,前面排了两队人,每个打饭阿姨同一时间只要应付一个同学,这就是并行

并发

  • 并发(concurrent)是同一时间应对(dealing with)多件事情的能力

还是打饭的例子,现在只有一个阿姨在打饭,但前面还是排了两队人,这样的话,阿姨一次要处理两个同学的打饭请求,这就是并发

Java线程

多线程的好处

前面介绍过,线程是操作系统进行调度的最小单位,一个线程同一时间只能运行在CPU的一个核心上,我们都知道,现在的CPU都是多核的。假如我们的程序只有一个线程,那么只会用到CPU的一个核心,那我们搞多核CPU不就浪费了吗,所以就需要多线程去提高程序的运行效率。打个比方,现在有个软件开发的任务,需要前端,后端,美工,但现在只有一个人身兼多职,其它几个人在边上喝茶,就相当于单线程运行,开发效率肯定不高。要是这几个人分工明确,齐心合作,开发效率自然就上去了。这就是多线程带来的好处。

创建和运行线程

1. 继承Thread ,重写run() 方法

第一种创建线程的方式是新建一个类继承自 Thread ,然后重写父类的 run() 方法,并在里面编写代码即可:

class MyThread extends Thread {

    @Override
public void run() {
System.out.println("创建了线程");
}
}

启动线程的方式很简单,只要创建MyThread类的实例,然后调用start()方法就行了:

new MyThread().start();

其实也可以简单一点,直接使用匿名类的方式,原理都是一样的:

new Thread() {
@Override
public void run() {
System.out.println("创建了线程");
}
}.start();

2. 实现Runnable接口

第一种方式的耦合性比较高,一般采用实现Runnable接口的方式去创建线程:

class MyThread implements Runnable {

    @Override
public void run() {
System.out.println("创建了线程");
}
}

启动线程的方式是创建Thread类的实例,接收一个Runnable参数,因为MyThread类实现了Runnable接口,所以把MyThread类的实例当作参数传入Thread类的构造方法,最后调用Thread类的start()方法就可以了。

new Thread(new MyThread()).start();

3. Callable+FutureTask

前面两种方式创建的线程都没有返回值,要想线程有返回值就可以使用第三种方式去创建线程:

FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 12345;
}
});
new Thread(task).start();
  • 让一个类实现Callable接口,重写里面的call方法,泛型就是返回值的类型,可以是任意数据类型。这里使用了匿名类的写法。
  • 创建一个FutureTask类的实例,将Callable对象作为参数传入其构造方法。
  • new一个Thread类的实例,将FutureTask对象当作参数传入,调用其start()方法启动线程。

这时候线程就成功创建并启动了,那怎么获取返回值呢?直接调用FutureTask的get()方法就可以了。

task.get();

这样就可以获取到返回值了,不过这里有个需要注意的地方,当调用get()方法的时候,线程就会阻塞在这里,直到成功获取返回值。我们可以来写段代码测试一下是不是这样:

FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
Thread.sleep(2000);
return 12345;
}
});
new Thread(task).start();
long start = System.nanoTime();
task.get(); //线程会阻塞在这里
long end = System.nanoTime();
long time = (end-start)/1000000;
System.out.println("耗费的时间为:"+time + "毫秒");

运行一下,看看结果:



从结果中可以看出,get()方法确实会阻塞线程。

4. 线程池

最后一种方式就是借助线程池,这也是《阿里巴巴Java开发手册》中推荐使用的方式。



但是比较尴尬的是我现在水平不够,还不会线程池

Java并发学习(一):进程和线程的更多相关文章

  1. Java并发编程:进程和线程之由来

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

  2. Java并发编程:进程和线程之由来__进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能

    转载自海子:http://www.cnblogs.com/dolphin0520/p/3910667.html Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨 ...

  3. java并发编程:进程和线程

    java并发编程涉及到很多内容,当然也包括多线程,再次补充点相关概念 原文地址:http://www.cnblogs.com/dolphin0520/p/3910667.html 一.操作系统中为什么 ...

  4. Java并发基础:进程和线程之由来

    转载自:http://www.cnblogs.com/dolphin0520/p/3910667.html 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程. ...

  5. Java并发编程 | 从进程、线程到并发问题实例解决

    计划写几篇文章讲述下Java并发编程,帮助一些初学者成体系的理解并发编程并实际使用,而不只是碎片化的了解一些Synchronized.ReentrantLock等技术点.在讲述的过程中,也想融入一些相 ...

  6. Java并发学习之中的一个——线程的创建

    本文是学习网络上的文章时的总结,感谢大家无私的分享. 1.与每一个Java语言中的元素一样,线程是对象.在Java中,我们有两种方式创建线程: a.通过直接继承thread类,然后覆盖run方法. b ...

  7. Java并发学习之十九——线程同步工具之Phaser

    本文是学习网络上的文章时的总结.感谢大家无私的分享. JDK 1.7 加入了一个新的工具Phaser.Phaser的在功能上与CountDownLatch有部分重合. 以下使用Phaser类来同步3个 ...

  8. java并发学习--第六章 线程之间的通信

    一.等待通知机制wait()与notify() 在线程中除了线程同步机制外,还有一个最重要的机制就是线程之间的协调任务.比如说最常见的生产者与消费者模式,很明显如果要实现这个模式,我们需要创建两个线程 ...

  9. java并发学习第五章--线程中的锁

    一.公平锁与非公平锁 线程所谓的公平,就是指的是线程是否按照锁的申请顺序来获取锁,如果是遵守顺序来获取,这就是个公平锁,反之为非公平锁. 非公平锁的优点在于吞吐量大,但是由于其不是遵循申请锁的顺序来获 ...

  10. java并发学习--第三章 线程安全问题

    线程的安全问题一直是我们在开发过程中重要关注的地方,出现线程安全问题的必须满足两个条件:存在着两个或者两个以上的线程:多个线程共享着共同的一个资源, 而且操作资源的代码有多句.接下来我们来根据JDK自 ...

随机推荐

  1. FarmCraft,又是Dp

    题目依然链接 题意: 从根节点出发,每条边走两遍回到根节点,走边用时1,到达某个节点之后开始计时,到该节点最大的计时数时结束,回到根节点时根节点开始计时.求让所有计时都结束的最小时间. Solve: ...

  2. 最近用unity写三消游戏,mark一个准备用的unity插件,用来控制运动。

    http://www.pixelplacement.com/itween/index.php itween 听说还不错!

  3. day52 html进阶

    目录 一.分组与嵌套 二.伪类选择器 三.伪元素选择器 四.选择器优先级 五.css属性相关 1 字体属性 2 文字属性 3 背景图片 4 边框 5 display属性 6 盒子模型 7 浮动 一.分 ...

  4. 二、python 中五种常用的数据类型

    一.字符串 单引号定义: str1 = 'hello' 双引号定义: str1 = "hello" 三引号定义:""" 人生苦短, 我用python! ...

  5. 数据可视化之PowerQuery篇(四)二维表转一维表,看这篇文章就够了

    https://zhuanlan.zhihu.com/p/69187094 数据分析的源数据应该是规范的,而规范的其中一个标准就是数据源应该是一维表,它会让之后的数据分析工作变得简单高效. 在之前的文 ...

  6. Python面向对象04 /封装、多态、鸭子类型、类的约束、super

    Python面向对象04 /封装.多态.鸭子类型.类的约束.super 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 3. 鸭子类型 4. 类的 ...

  7. 图文详解在Windows系统中安装JDK

    本文以在Windows10中安装JDK8为例进行安装,其他系统和版本都是大同小异的. 下载 进入Oracle官方网站的下载页面:https://www.oracle.com/technetwork/j ...

  8. 关于python爬取异步ajax数据的一些见解

    我们在利用python进行爬取数据的时候,一定会遇到这样的情况,在浏览器中打开能开到所有数据,但是利用requests去爬取源码得到的却是没有数据的页面框架. 出现这样情况,是因为别人网页使用了aja ...

  9. 媳妇儿让我给她找一个PDF转word免费工具,找了半天我决定给她写一个出来^-^

    ​ 之前我媳妇儿让我给她找一个PDF转WORD的免费工具,在网上找了半天发现要不就是收费,要不就是转化的格式混乱.既然网上不能找到好用的免费工具那就直接来写一个吧.人生苦短,我用python. 万能的 ...

  10. 评测Loki日志工具

    评测Loki日志工具 目录 评测Loki日志工具 部署Loki 配置grafana 总结: 优势: 劣势: 本文仅对Loki进行简单评测,不涉及原理和细节. 部署Loki Loki是grafana团队 ...