Java多线程1:进程与线程
进程和线程
讲线程和进程前,先讲下同步(Synchronous)、异步(Asynchronous)、并发(Concurrency)、并行(Parallelism)。
同步(Synchronous)和异步(Asynchronous)
同步和异步通常来形容一次方法调用,同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就
可以继续后续的操作。而异步方法通常会在另外一个线程中“真实”地执行。整个过程,不会阻碍调用者的工作。
打个比方,比如购物,如果你去商场买空调,当你到了商场看重了一款空调,你就向售货员下单。售货员去仓库帮你调配物品。这天你热的是在不行了,就催着商家赶紧给你送货,于是你就在商店里面候着他们,
直到商家把你和空调一起送回家,一次愉快的购物就结束了。这就是同步调用。
不过,如果我们赶时髦,就坐在家里打开电脑,在电脑上订购了一台空调。当你完成网上支付的时候,对你来说购物过程已经结束了。虽然空调还没有送到家,但是你的任务已经完成了。商家接到你的订单后,
就会加紧安平送货,当然这一切已经跟你无关了。你已经支付完成,想干什么就能去干什么,出去溜几圈都不成问题,等送货上门的时候,接到商家的电话,回家一趟签收就完事了。这就是异步调用。
并发(Concurrency)和并行(Parallelism)
并发和并行是两个非常容易被混淆的概念。他们都可以表示两个或者多个任务一起执行,但是侧重点有所不同。
并发偏重于多个任务交替执行,而多个任务之间有可能还是串行的,而并行是真正意义上的“同时执行”。
大家排队在一个咖啡机上接咖啡,交替执行,是并发;两台咖啡机上面接咖啡,是并行。
从严格意义上来说,并行的多任务是真的同时执行,而对于并发来说,这个过程只是交替的,一会执行任务A,一会执行任务B,系统会不停地在两者之间切换。但对于外部观察者来说,即使多个任务之间是串行并发的,也会造成多任务间并行执行的错觉。
并发说的是在一个时间段内,多件事情在这个时间段内交替执行。
并行说的是多件事情在同一个时刻同事发生。
实际上,如果系统内只有一个CPU,而使用多进程或者多线程任务,那么真实环境中这些任务不可能是真实并行的,毕竟一个CPU一次只能执行一条指令,在这种情况下多进程或者多线程就是并发的,而不是并行的(操作系统会不停地切换多任务)。真实的并行也只可能出现在拥有多个CPU的系统中(比如多核CPU)。
我们再讲进程和线程的概念。
进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。
进程具有的特征:
动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的
并发性:任何进程都可以同其他进行一起并发执行
独立性:进程是系统进行资源分配和调度的一个独立单位
结构性:进程由程序,数据和进程控制块三部分组成
360浏览器是一个进程、WPS也是一个进程,正在操作系统中运行的".exe"都可以理解为一个进程。
我们双击.exe文件的时候,这个文件中的指令就会被系统加载,那么我们就能得到一个关于这个.exe程序的进程。进程是“活”的,或者说是正在被执行的。
线程
进程中独立运行的子任务就是一个线程。像QQ.exe运行的时候就有很多子任务在运行,比如聊天线程、好友视频线程、下载文件线程等等。
一个程序至少有一个进程,一个进程至少有一个线程。
使用多线程而不是多进程去进行并发程序的设计,是因为线程间的切换和调度的成本远远小于进程。
多线程源码:https://github.com/xiaojiesir/Multithreading
创建线程的方式
创建线程有两种方式:
1、继承Thread,重写父类的run()方法。
public class MyThread00 extends Thread
{
public void run()
{
for (int i = 0; i < 5; i++)
{
System.out.println(Thread.currentThread().getName() + "在运行!");
}
}
}
public static void main(String[] args)
{
MyThread00 mt0 = new MyThread00();
mt0.start(); for (int i = 0; i < 5; i++)
{
System.out.println(Thread.currentThread().getName() + "在运行!");
}
}
看一下运行结果:
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
Thread-0在运行!
main在运行!
看到main线程和Thread-0线程交替运行,效果十分明显。
2、实现Runnable接口。和继承自Thread类差不多,不过实现Runnable后,还是要通过一个Thread来启动:
public class MyThread01 implements Runnable
{
public void run()
{
for (int i = 0; i < 5; i++)
{
System.out.println(Thread.currentThread().getName() + "在运行!");
}
}
}
public static void main(String[] args)
{
MyThread01 mt0 = new MyThread01();
Thread t = new Thread(mt0);
t.start(); for (int i = 0; i < 5; i++)
{
System.out.println(Thread.currentThread().getName() + "在运行!");
}
}
效果也十分明显:
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
3、实现Callable接口,实现call方法。这个比较复杂,先简单说明下,后续详细讲。有两种方法
先定义一个类实现callable接口
class ThreadDemo implements Callable<Integer> { @Override
public Integer call() throws Exception {
int sum = 0; for (int i = 0; i <= 100000; i++) {
sum += i;
} return sum;
} }
通过FutureTask包装器来创建Thread线程
ThreadDemo td = new ThreadDemo();
//通过FutureTask包装器来创建Thread线程,用于接收运算结果。
FutureTask<Integer> result = new FutureTask<Integer>(td);
new Thread(result).start();
5 System.out.println(result.get());
使用ExecutorServices.submit()方法调用它
ThreadDemo td = new ThreadDemo();
//利用ExecutorServices.submit()的方法调用
ExecutorService exec=Executors.newCachedThreadPool();
Future<Integer> results=exec.submit(td);
System.out.println(results.get());
它与Runnable的区别在于它有返回值,可以抛出异常。runnable无返回值,不能抛出异常。
两种多线程实现方式的对比
看一下Thread类的API:
其实Thread类也是实现的Runnable接口。两种实现方式对比的关键就在于extends和implements的对比,当然是后者好。因为第一,继承只能单继承,实现可以多实现;第二,实现的方式对比继承的方式,也有利于减小程序之间的耦合。
线程状态
虚拟机中的线程状态有六种,定义在Thread.State中:
1、新建状态NEW
new了但是没有启动的线程的状态。比如"Thread t = new Thread()",t就是一个处于NEW状态的线程
2、可运行状态RUNNABLE
new出来线程,调用start()方法即处于RUNNABLE状态了。处于RUNNABLE状态的线程可能正在Java虚拟机中运行,也可能正在等待处理器的资源,因为一个线程必须获得CPU的资源后,才可以运行其run()方法中的内容,否则排队等待
3、阻塞BLOCKED
如果某一线程正在等待监视器锁,以便进入一个同步的块/方法,那么这个线程的状态就是阻塞BLOCKED
4、等待WAITING
某一线程因为调用不带超时的Object的wait()方法、不带超时的Thread的join()方法、LockSupport的park()方法,就会处于等待WAITING状态
5、超时等待TIMED_WAITING
某一线程因为调用带有指定正等待时间的Object的wait()方法、Thread的join()方法、Thread的sleep()方法、LockSupport的parkNanos()方法、LockSupport的parkUntil()方法,就会处于超时等待TIMED_WAITING状态
6、终止状态TERMINATED
线程调用终止或者run()方法执行结束后,线程即处于终止状态。处于终止状态的线程不具备继续运行的能力。
Java多线程1:进程与线程的更多相关文章
- Java多线程之进程和线程
在并发编程中有两个基本的概率就是进程和线程.在Java编程中并发编程更多的是关注线程.但是进程也是很重要的. 一个计算机一般会有很多活跃的进程和线程.有一点是没有疑问的在单核系统中,任何时候实际上都是 ...
- -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait( ...
- Java中的进程和线程
Java中的进程与线程 一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是 ...
- Java中的进程与线程(总结篇)
详细文档: Java中的进程与线程.rar 474KB 1/7/2017 6:21:15 PM 概述: 几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进 ...
- Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)
一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...
- Java多线程(一) —— 线程的状态详解
一.多线程概述 1. 进程 是一个正在执行的程序.是程序在计算机上的一次运行活动. 每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控制单元. 系统以进程为基本单位进行系统资源的调度 ...
- Java多线程(五)线程的生命周期
点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...
- java 获取当前进程id 线程id
java 获取当前进程id 线程id RuntimeMXBean (Java Platform SE 8 ) https://docs.oracle.com/javase/8/docs/api/j ...
- Java多线程-同步:synchronized 和线程通信:生产者消费者模式
大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...
- C# - 多线程 之 进程与线程
并行~并发 并发 Concurrency,逻辑上的同时发生,一个处理器(在不同时刻或者说在同一时间间隔内)"同时"处理多个任务.宏观上是并发的,微观上是按排队等待.唤醒.执行的步骤 ...
随机推荐
- 虚拟化技术之kvm磁盘管理工具qemu-img
在前边的博客中,我们大致了解了virsh这个工具对kvm虚拟机的一些操作,回顾请参考https://www.cnblogs.com/qiuhom-1874/tag/virsh/:今天我们来了解下kvm ...
- 更换IntelliJ Idea的Terminal为git_home/bin/sh.exe命令端程序
idea中默认的terminal形式: 1.在IDEA中,打开settings,设置相应的bash路径 settings–>Tools–>Terminal–>Shell path:C ...
- JavaScript学习系列博客_28_JavaScript 数组去重
数组去重 var arr = [1,2,3,2,2,1,3,4,2,5]; //去除数组中重复的数字 //获取数组中的每一个元素 for(var i=0 ; i<arr.length ; i++ ...
- Java并发篇
Java并发篇 作者:星晴(当地小有名气,小到只有自己知道的杰伦粉) 1. Java锁 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 Synchronized 同步锁 1.4.1 核心组件 ...
- oracle进行一对多关联查询的时候,获取副表(也就是多条记录的那张表)的最新一条记录进行关联,如何获取多条记录最新一条呢?
例如以下场景: 一条新闻对应多条审核记录,用户想知道这条新闻走到哪一步审核了. 使用:select * from (select b.*,(ROW_NUMBER() OVER (PARTITION B ...
- java父类子类代码
import java.util.Scanner;import java.util.*; class PersonF{ public void print(String ID,String Workc ...
- SpringMVC中前端Form表单提交后跳转不过去的问题
今天晚上打算谢谢Spring整合这个内容,写的差不多之后运行 出现了各种问题 逐一排查 首先有一个(MyEclipse10) 一: class path resource [spring-mvc.xm ...
- C#封装定时执行任务类
a.日常开发中经常会遇到定时去执行一些操作,比如定时更新数据.A类需要做我们写个Timer定时去取数据,这时候B类,C类也需要做这样的事情,是不是需要写三次重复代码? 这时候把timer封装成一个帮助 ...
- android开发之java代码中字符串对比忽略大小写。java程序员必回,可用来比对验证码等问题
比如:字符串a与字符串B对比,只需调用 a.equalsIgnoreCase(B);即可.很简单的一个方法.忽略大小写.
- Android开发之将Edittext输入弹出的软键盘设置搜索确定键。详细代码,已验证可用。
1,首先在布局中添加 android:imeOptions="actionSearch 2,然后java代码中设置代码: et_input_password.setOnEditorActio ...