Java并发学习(一):进程和线程
好好学习,天天向上
本文已收录至我的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并发学习(一):进程和线程的更多相关文章
- Java并发编程:进程和线程之由来
Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...
- Java并发编程:进程和线程之由来__进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能
转载自海子:http://www.cnblogs.com/dolphin0520/p/3910667.html Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨 ...
- java并发编程:进程和线程
java并发编程涉及到很多内容,当然也包括多线程,再次补充点相关概念 原文地址:http://www.cnblogs.com/dolphin0520/p/3910667.html 一.操作系统中为什么 ...
- Java并发基础:进程和线程之由来
转载自:http://www.cnblogs.com/dolphin0520/p/3910667.html 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程. ...
- Java并发编程 | 从进程、线程到并发问题实例解决
计划写几篇文章讲述下Java并发编程,帮助一些初学者成体系的理解并发编程并实际使用,而不只是碎片化的了解一些Synchronized.ReentrantLock等技术点.在讲述的过程中,也想融入一些相 ...
- Java并发学习之中的一个——线程的创建
本文是学习网络上的文章时的总结,感谢大家无私的分享. 1.与每一个Java语言中的元素一样,线程是对象.在Java中,我们有两种方式创建线程: a.通过直接继承thread类,然后覆盖run方法. b ...
- Java并发学习之十九——线程同步工具之Phaser
本文是学习网络上的文章时的总结.感谢大家无私的分享. JDK 1.7 加入了一个新的工具Phaser.Phaser的在功能上与CountDownLatch有部分重合. 以下使用Phaser类来同步3个 ...
- java并发学习--第六章 线程之间的通信
一.等待通知机制wait()与notify() 在线程中除了线程同步机制外,还有一个最重要的机制就是线程之间的协调任务.比如说最常见的生产者与消费者模式,很明显如果要实现这个模式,我们需要创建两个线程 ...
- java并发学习第五章--线程中的锁
一.公平锁与非公平锁 线程所谓的公平,就是指的是线程是否按照锁的申请顺序来获取锁,如果是遵守顺序来获取,这就是个公平锁,反之为非公平锁. 非公平锁的优点在于吞吐量大,但是由于其不是遵循申请锁的顺序来获 ...
- java并发学习--第三章 线程安全问题
线程的安全问题一直是我们在开发过程中重要关注的地方,出现线程安全问题的必须满足两个条件:存在着两个或者两个以上的线程:多个线程共享着共同的一个资源, 而且操作资源的代码有多句.接下来我们来根据JDK自 ...
随机推荐
- 四维DP之方格取数
题目描述 传送门 设有N*N的方格图(N<=20,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样例): 某人从图的左上角的A(1,1) 点出发,可以向下行走,也可 ...
- P3295 萌萌哒 题解
题目 一个长度为n的大数,用\(S_1,S_2,S_3...S_n\)表示,其中\(S_i\)表示数的第\(i\)位,\(S_1\)是数的最高位,告诉你一些限制条件,每个条 件表示为四个数,\(l_1 ...
- day79 组件化开发
目录 一.组件[component] 默认组件 二. Vue自动化工具(Vue-cli) 1 安装node.js 2 npm 3 安装Vue-cli 4 使用Vue-CLI初始化创建前端项目 4.1 ...
- 题解:2018级算法第四次上机 C4-商人卖鱼
题目描述: 样例: 实现解释: 需要简单分析的贪心题 知识点: 贪心,自定义排序,提前存储 题目分析: 卖鱼,鱼卖出去需要时间,鱼没被卖出去之前需要吃饲料 则有,如果卖a鱼的话b鱼会吃饲料c份,而卖b ...
- FileBeat yml配置文件 -常用参数详解
#filebeat 5.2.2 #prospector(input)段配置 filebeat.prospectors: #每一个prospectors,起始于一个破折号"-" - ...
- AcWing 94. 递归实现排列型枚举
AcWing 94. 递归实现排列型枚举 题目链接 把 1~n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序. 输入格式 一个整数n. 输出格式 按照从小到大的顺序输出所有方案,每行1个. ...
- 隐藏Layer中的Iframe内部元素
隐藏Layer中的Iframe内部元素 1.Layer:一个web弹出层/窗解决方案 2.隐藏Layer弹出层中Iframe内部的元素,例子如下: 这个就是在Layer弹出层内的内容,加载完毕之后,获 ...
- 重学c#系列——c# 托管和非托管资源(三)
前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...
- 牛客网Java工程师能力评估
感觉很奇怪,出的题做完之后感觉自己没学过Java一样,不过凭借一些做题的技巧和一些记忆,正确率百分之50,排名前百分之30多,记录一下这次的题目,方便我以后进行二次复习吧 1.下面有关JVM内存,说法 ...
- GPO - Set Date and Time for Updates
For Windows Update, the limitation normally is a time window, disk space, network bandwidth. Create ...