详解Java并发编程基础,并发编程其实并不难(附:并发编程图谱)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了详解Java并发编程基础,并发编程其实并不难(附:并发编程图谱),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5733字,纯文字阅读大概需要9分钟。
内容图文
![详解Java并发编程基础,并发编程其实并不难(附:并发编程图谱)](/upload/InfoBanner/zyjiaocheng/644/61647691616c4d19a0f7d589735def70.jpg)
本文转载自:详解Java并发编程基础,并发编程其实并不难(附:并发编程图谱)
一、什么是线程和进程
在介绍什么是线程之前,有必要对进程进行了解下,在操作系统中线程是进程中的一个实体,线程并不会独立存在,进程是资源分配和调度的基本单位,一个进程中最少有一个线程,多个线程共享一个进程内的资源。
- 进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源
- 线程:CPU调度的最小单位,必须依赖进程而存在。
二、什么是并发和并行
- 并行:指两个或多个事件在同一时间点发生。列如我们在学生时代,排队打饭,有多个窗口可以同时排队打饭。这就是并行。
- 并发:指单位时间内,处理事情的能力。列如我们在排队打饭时,单个窗口5分钟内可以处理10个人打饭,这就叫做并发。
三、什么是同步和异步
- 同步:所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。
- 异步:异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个调用完成后,一般通过状态、通知和回调来通知调用者。对于异步调用,调用的返回并不受调用者控制。
四、如何学习好java并发编程
是不是总有一种感觉,在项目开发遇到问题时,打比方在了解一些并发工具类的使用时,会查阅相关资料,但过段时间又忘了,总感觉我已经学习了好多知识,但还是搞不懂,有时候好不容易解决这个问题,但又不知道这样做是不是对的或者是最优方案,那怎么样才能学习好并发编程? 其实在之前我也遇到过这样的问题,其实就2点,一个是从现象看本质,深入源码学习,二个是对整体并发工具类有个大体了解,最起码能知道有哪些工具类,在解决实际问题中,他们的优缺点是什么。有些人会问,那我已经知道这些并发工具类的使用用途,源码也看了,但他们为什么这样设计,这样设计有什么好处,我只能说这样的问题只有问并发编程大师Doug Lea了。附带一张java并发编程图谱
五、Java多线程并发三个核心问题:分工、同步和互斥
- 分工:列如在装修房屋时,装修公司的工作就是把房屋装修好,交接给客户进行验收,装修公司在安排任务时为了提高效率,安排木工负责打衣柜、橱柜,电工负责电线铺设等,通俗点讲就是安排不同的人做不同的事。在Java世界里,Java SDK 并发包里的 Executor、Fork/Join、Future本质上也是一种分工。
- 同步:不过是一个线程执行完了一个任务,如何通知执行后续任务的线程开工而已
- 互斥:所谓互斥,指的是同一时刻,只允许一个线程访问共享变量。
六、在JDK中已经明确说明了只有2中方式创建线程如下,第一种就是实现Runable接口的run方法、第二种就是继承Thread类重写run方法,另外一种大多数人可能会认为是第3种方式实现Callable接口,
There are two ways to create a new thread of execution. One is to
declare a class to be a subclass of <code>Thread</code>. This
subclass should override the <code>run</code> method of class
<code>Thread</code>. An instance of the subclass can then be
allocated and started. For example, a thread that computes primes
larger than a stated value could be written as follows:
1. 通过实现Runable接口,如下
public class RunableTest {
public static class RunableTask implements Runnable{
@Override
public void run() {
System.out.println("hello world");
}
}
public static void main(String[] args) {
RunableTask RunableTask = new RunableTask();
Thread thread = new Thread(RunableTask);
thread.start();
}
}
上述代码实现Runable接口的run方法,这样做的好处是RunableTask可以在继承其他类利于扩展,坏处是不能用this关键字获取当前线程相关信息,必须通过Thread.currentThread()方法来获取。
2. 通过继承Thread类,如下
public class ThreadTest extends Thread {
public static class ThreadTask extends Thread{
@Override
public void run() {
System.out.println("hello world");
}
}
public static void main(String[] args) {
ThreadTask threadTask = new ThreadTask();
threadTask.start();
}
}
- 上述代码创建一个ThreadTest类,在main函数中创建ThreadTest的实例,并调用start方法启动线程。注意当然调用start方法后,线程并没有马上执行,而是处于就绪状态,这个就绪状态指线程除了获取CPU资源外已经获取了其他资源,等待获取CPU资源后才真正是运行状态,当然运行完run方法后,线程终止结束。
- 继承的好处是可以在run方法中直接可以使用this关键字获取当前线程相关信息,而不用在使用Thread.currentThread()法,但坏处是,我们都知道java是单继承,这样做不利于扩展。
3. 通过实现Callable接口,如下
public class CallableTest {
public static class CallableTask implements Callable<String>{
@Override
public String call() {
return "hello world";
}
}
public static void main(String[] args) {
try {
CallableTask callableTask = new CallableTask();
FutureTask<String> futureTask = new FutureTask<>(callableTask);
new Thread(futureTask).start();
String res = futureTask.get();
System.out.println(res);
}catch (Exception e){
e.printStackTrace();
}
}
}
- 上述代码是通过FutureTask方式运行线程。
- 它比Runable和Thread的优点是它可以有返回值,缺点是在使用FutureTask的get方法获取返回值时它是阻塞的。
- call接口可以抛出异常,而Runable必须通过setUncaughtExceptionHandler()设置异常,才能在主线程中捕获到子线程的异常。
- 调用start方法后再次调用报IllegalThreadStateException异常,如下源码所示
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
4. 他们3者关系如下
七、Java线程的生命周期
1. java线程的生命周期如下图所属(图片来源于网络和书籍)
- 如上图所式,线程有5中状态 新建状态(NEW)、就绪状态(RUNNABLE)、运行状态(RUNNING)、阻塞状态(BLOCKED)、死亡状态(DADE)
- NEW新建状态,是创建线程未启动状态
本文转载自:详解Java并发编程基础,并发编程其实并不难(附:并发编程图谱)
Java_supermanNO1 发布了220 篇原创文章 · 获赞 20 · 访问量 2万+ 私信 关注内容总结
以上是互联网集市为您收集整理的详解Java并发编程基础,并发编程其实并不难(附:并发编程图谱)全部内容,希望文章能够帮你解决详解Java并发编程基础,并发编程其实并不难(附:并发编程图谱)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。