大家好,今天来为大家分享深入解析多线程原理:线程安全及其保证策略的一些知识点,和的问题解析,大家要是都明白,那么可以忽略,如果不太清楚的话可以看看本篇文章,相信很大概率可以解决您的问题,接下来我们就一起来看看吧!
为什么有多个线程?什么是线程安全?如何保证线程安全?
为什么会有多线程
显然,线程安全问题只会出现在多线程环境下,那么为什么会有多线程呢?
最早的计算机非常原始,没有操作系统。当人们要使用计算机时,首先将计算机可以执行的指令写在纸带上,然后让计算机从纸带上读取每条指令并依次执行。此时计算机一次只能执行一项任务,是纯粹的单线程。
这样的话,就出现了三个问题:
1. 计算资源的严重浪费计算机在执行任务时,总会有一些输入输出操作,比如计算结果的打印等,此时CPU只能等待输入输出完成。因此,往往一个任务执行完毕后,CPU可能大部分时间都处于空闲状态。当时CPU是一种非常昂贵的资源,于是人们就思考如何提高CPU的利用率?
2. 任务分配的不公平现在,如果我们有十个任务要执行,这很常见。计算机一次只能执行一项任务,直到执行结束,中间不能被中断。那么问题来了,我们是不是应该先执行张三交给的任务呢?还是先做李四的工作?张三和李四的优先级可能是一样的,所以无论任务如何分配,总会有人不满意,觉得不公平。
3. 程序编写十分困难计算机一次只能执行一项任务,因此在编写程序时,往往需要将大量的工作集成到一个程序中,这给程序员带来了很大的挑战。能否将程序写成模块,然后模块之间只进行必要的通信?
为了解决这些问题,计算机操作系统应运而生。操作系统是管理计算机硬件和软件资源的计算机程序。那么操作系统是如何同时执行多个任务的呢?操作系统为每个任务分配一个进程,然后给进程分配相应的计算资源、IO资源等,使进程能够执行。操作系统会控制多个进程之间的切换,为每个进程分配一定的执行时间,然后切换到另一个进程,这样多个进程就可以轮流交替执行。由于轮次很短,用户会感觉自己好像在垄断计算机资源来执行任务。
虽然该流程在一定程度上缓解了我们提到的三个问题,但仍然存在问题。让我举两个例子。一个例子是一个进程只能做一件事,或者进程中的代码是串行执行的。这有什么问题吗?当然有。例如,我们使用软件安装包来安装程序。在安装过程中,我们突然不想再安装了,然后点击取消按钮。结果我们发现程序并没有取消安装。为什么?由于该进程正在执行安装程序代码,因此在安装程序代码完成之前无法执行用户输入。所以你发现当进程响应你的取消安装的输入时,安装程序已经完成了。用专业的话说,用户界面的响应能力太差了。用户输入无法立即响应,界面甚至可能出现暂停状态。另一个例子是当今大多数处理器都是多处理器。例如,现在有一个双处理器,只有一个任务。那么这个任务只能由一个进程执行,而一个进程只能由一个处理器执行,那么就浪费了50%的计算资源。
这个时候就该说说线程了。线程是进程中进行调度和分派的基本单位。一个进程可以有多个线程,但至少有一个线程;并且一个线程只能在一个进程的地址空间内活动。内存资源分配给进程,同一进程的所有线程共享该进程的所有资源。 CPU被分配给线程,也就是说,线程实际上是在处理器上运行的。多线程的出现解决了我们之前提到的三个问题,但是多线程往往会带来很多意想不到的问题。这就是我们接下来要讲的线程安全。
什么是线程安全
在讲线程安全问题之前,先给大家举一个线程不安全的例子,直接上代码。
公开课测试{
私有静态int 计数;
私有静态类Thread1 扩展Thread {
公共无效运行(){
for (int i=0; i 1000; i++) {
计数++;
尝试{
线程.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
公共静态无效主(字符串[] args)抛出InterruptedException {
线程1 t1=新线程1();
线程1 t2=新线程1();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(count);
}
}这段代码实现的逻辑非常简单。首先定义一个int类型的count变量,然后启动两个线程。每个线程执行循环1000次,并将循环中的计数加1。等待两个线程完成执行后,打印count的值。那么这段代码的输出是什么?很多人可能会说是2000,但是程序运行后发现结果很可能不是2000,而是一个比2000稍小的数字,比如1998,而且每次的结果可能都不一样跑步。
那么这是为什么呢?这是线程不安全的。线程安全是指在多线程环境下,程序始终能够执行正确的行为,符合预期的逻辑。例如,我们刚刚的程序有两个线程。每个线程累加count 变量1000 次。预期的逻辑是count累加2000次,但是代码执行的结果不是2000,所以是线程不安全的。
为什么不安全?因为count++指令在实际执行过程中并不是原子的,而是分为读、修改、写三个步骤;即先从内存中读取count的值,然后进行+1操作,然后将结果相加写回内存,如下图所示。
形象地说,这就是计算机中线程的实际执行过程。看起来好像没有什么问题。别着急,看另一张图。
图片你看到问题了吗?上图中,线程1执行了两次自增操作,线程2执行了一次自增操作,但是计数从6变成了8,只加了2。我们来看看为什么会出现这种情况。当线程1完成读取count的值到6后,切换到线程2执行。线程2也读取到count的值为6,然后进行更改写入操作,count的值变成7;这时,线程2切换回线程1,但是线程1中的count的值还是线程2中修改前的6,这就是问题所在!即线程2修改了count的值,但是这个修改对于线程1来说是不可见的,这就导致程序变得线程不安全,不符合我们期望的逻辑。
相信现在大家对于线程不安全已经有了一定的了解。现在我们来总结一下导致线程不安全的原因。主要有以下三点:
【深入解析多线程原理:线程安全及其保证策略】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
我最近在学习并发编程,这个标题听起来很有用!
有17位网友表示赞同!
确实想了解下多线程有什么好处,以及线程安全怎么弄啊。
有19位网友表示赞同!
感觉多线程能让我处理任务更快,但如果线程不安全会出问题吗?
有7位网友表示赞同!
我一直听说并发编程很复杂,这个标题好像可以解答我的疑问!
有9位网友表示赞同!
想明白为什么需要多线程,才能更好地理解如何保证安全吧。
有19位网友表示赞同!
多线程是不是比单线程更复杂的操作啊?
有18位网友表示赞同!
学习一下线程相关的知识,感觉对软件开发的理解会更深入!
有14位网友表示赞同!
这个标题非常精准,涵盖了多线程的核心问题!
有12位网友表示赞同!
看来保证线程安全很重要,否则程序可能会崩溃吧。
有14位网友表示赞同!
希望这篇文章能详细讲解每个概念,让我能够全面了解 。
有13位网友表示赞同!
多线程的应用场景挺广泛的,想学习一下实际案例!
有5位网友表示赞同!
看评论都是说这个问题很难懂,希望能有详细的解释!
有12位网友表示赞同!
我也被线程安全的概念搞 confused 呀 ,也许这篇文能解开我的疑惑。
有19位网友表示赞同!
多线程和多进程的区别是什么?文章里有解答吗?
有11位网友表示赞同!
学习编程总是要碰到这些难题,期待作者给出有效的方法!
有5位网友表示赞同!
对这三个概念一直不是很了解,希望能好好阅读这篇文章!
有15位网友表示赞同!
感觉学习多线程技术很有挑战性,也需要不断实践才能掌握。
有18位网友表示赞同!
想要写更优秀的程序,必须得理解这些基础知识呀
有17位网友表示赞同!
希望这篇文章能让我对多线程和线程安全有更深入的理解!
有18位网友表示赞同!