01线程安全

线程安全的解释是:

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

线程安全问题都是由全局变量及静态变量引起的。

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全

对于线程安全类的实例进行顺序或并发的一系列操作。都不会导致实例处于无效状态。

1.什么是无效状态

有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。 无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象.不能保存数据,是不变类,是线程安全的。 

无状态线程永远都是线程安全的。例如:

public class StatelessServlet extends HttpServlet {

@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int integer = 100;
System.out.println("我不影响其他进程");
}
}

当我们定义状态元素,一个全局变量,然后在service中进行操作,则不是线程安全的了。

public class StatelessServlet extends HttpServlet {
private int count = 0;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int integer = 100;
count++;
System.out.println("我不影响其他进程");
}
}

当两个线程进行调用,实际应该等于12,但是可能会出现等于11

在处理的过程中,相对于在同一状态下的其他操作而言,必须是原子性或不可分割的,为了避免竞争条件,必须阻止其他线程访问我们正在修改的变量,保证在我们修改完成后再近些操作。

2.锁

内置锁机制:synchronized块(由锁对象的引用,锁保护的代码块组成),synchronized方法的锁(锁对象本身,如果是静态的synchronized方法,则从class对象上获取锁)

synchronized(lock){

访问或修改被锁保护的共享状态

}

内部锁扮演着互斥锁,执行现场进入synchronized块之前会自动获得锁,如java对象(可以隐式作为一个同步锁的角色)。当正常退出或从异常代码库中退出,都会自动释放锁。获得锁的唯一路径:进入该内部锁保护的同步块或方法。

建议不这样做(给service的方法加上同步锁)

public class StatelessServlet extends HttpServlet {
private int count = 0;
@Override
protected synchronized void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int integer = 100;
count++;
System.out.println("我不影响其他进程");
}
}

对于每一个涉及多个变量的不变约束,都需要同一个锁保护其所有变量。[自己理解:当我们需要多个变量修改,必须保证这多个变量要在同一个锁下面]

3.活跃度与性能

上面我们在service方法上加上了同步锁,但是这样会导致多个请求排队一个个进行接收处理,不能同步请求service方法,代价高昂,Service是处理多请求的,这样显然是不合理的,

解决办法:

缩小synchronized的范围来维护现场安全性,可容易提高线程安全性。

通常简单性与性能之间是相互牵制的,实现一个同步策略时,不要过早地为了性能而牺牲简单些,有些耗时的计算或操作,比如网络或控制台I/O,难以快速完成,执行这些操作期间不要占有锁。

时间: 2024-10-24 11:39:38

01线程安全的相关文章

c#线程-线程同步(halcon论坛网友提供)

线程同步 如果有多个线程同时访问共享数据的时候,就必须要用线程同步,防止共享数据被破坏.如果多个线程不会同时访问共享数据,可以不用线程同步. 线程同步也会有一些问题存在: 性能损耗.获取,释放锁,线程上下文建切换都是耗性能的. 同步会使线程排队等待执行. 线程同步的几种方法: 阻塞 当线程调用Sleep,Join,EndInvoke,线程就处于阻塞状态(Sleep使调用线程阻塞,Join.EndInvoke使另外一个线程阻塞),会立即从cpu退出.(阻塞状态的线程不消耗cpu) 当线程在阻塞和非

Java多线程并发09——如何实现线程间与线程内数据共享

本文将为各位带来 Java 阻塞队列相关只是.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程间数据共享 Java 里面进行多线程通信的主要方式就是共享内存的方式,共享内存主要的关注点有两个:可见性和有序性原子性.Java 内存模型(JMM)解决了可见性和有序性的问题,而锁解决了原子性的问题,理想情况下我们希望做到"同步"和"互斥".有以下常规实现方法: 将数据抽象成一个类 将数据抽象成一个类,并将对这个数据的操作作为这个类的方法,这么设计可以和

如何优雅的关闭Java线程池

面试中经常会问到,创建一个线程池需要哪些参数啊,线程池的工作原理啊,却很少会问到线程池如何安全关闭的. 也正是因为大家不是很关注这块,即便是工作三四年的人,也会有因为线程池关闭不合理,导致应用无法正常stop的情况,还有出现一些报错的问题. 本篇就以ThreadPoolExecutor为例,来介绍下如何优雅的关闭线程池. 01 线程中断 在介绍线程池关闭之前,先介绍下Thread的interrupt. 在程序中,我们是不能随便中断一个线程的,因为这是极其不安全的操作,我们无法知道这个线程正运行在

20160208.CCPP体系详解(0018天)

程序片段(01):main.c 内容概要:PointWithOutInit #include <stdio.h> #include <stdlib.h> //01.野指针详解: // 1.野指针:没有进行初始化操作的指针-->由于该指针变量内部所存储的地址是个随机值,因此是野地址(类型含义:指针) // 注:指针类型的变量必须在其被创建的时候就需要进行初始化操作,否则就成了野指针,所谓野指针就是乱指向的指针,形成的就是一个随机垃圾地址 // 2.胡乱使用野指针所造成的现象:

20160226.CCPP体系详解(0036天)

程序片段(01):01.多线程.c+02.多线程操作.c 内容概要:多线程 ///01.多线程.c #include <stdio.h> #include <stdlib.h> #include <Windows.h> #include <process.h> //01.线程任务函数剖析: // 1."封装"线程任务代码 // 2.MessageBox();作用: // 用于"阻塞"当前线程的继续执行状态 // 也就是

各科基础详实

一. Java基础部分 1. JAVA的基本数据类型有哪些 ?  String 是不是基本数据类型 ? 2. 一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 3. Java有没有goto? 7 4. 说说&和&&的区别. 7 5. 在JAVA中如何跳出当前的多重嵌套循环? 7 6. switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 8 7. short s1 = 1; s1 = s1 + 1;有什么

java中获取所有文件--(递归调用)

import java.io.File;import java.io.*; //获取一个文件夹中的所有的文件.  /*    打印要求:      -- a.txt   -- IO.doc      -- ~$IO.doc   -- 代码   -- --.metadata   -- --Day18   --视频   -- --01 线程通信.wmv   -- --02 守护线程和join方法.wmv   -- --03 Filed的创建.wmv   -- --04 File的常用方法.wmv  

多线程并发中的同步

多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问.参考自http://www.cnblogs.com/phinecos/archive/2010/03/13/1684877.html 实例说明:1.貌似同步,实际不同步的情况 package com.thread.code.sync; /** * 不能实现线程同步的例子 * @author 魅力_小生 * @version [版本号, 2016年3月4日] */ public class

20160208.CCPP体系具体解释(0018天)

程序片段(01):main.c 内容概要:PointWithOutInit #include <stdio.h> #include <stdlib.h> //01.野指针具体解释: // 1.野指针:没有进行初始化操作的指针-->由于该指针变量内部所存储的地址是个随机值,因此是野地址(类型含义:指针) // 注:指针类型的变量必须在其被创建的时候就须要进行初始化操作,否则就成了野指针,所谓野指针就是乱指向的指针,形成的就是一个随机垃圾地址 // 2.胡乱使用野指针所造成的现象