1 不可变对象

用不可变对象保证线程安全,是相当于不让线程并发,逃避了并发。

不可变对象就是指一个类的实例化对象不可变。比如String类的实例

主要方法有:

  将类声明为final

  将所有成员声明为 private

  对变量不提供 set 方法,将所有可变成员声明为 final,只能赋值一次,通过构造器初始化所有成员,进行深度拷贝

  在 get 方法中不直接返回对象本身,而是克隆对象,并返回对象的拷贝。

final关键字

一个类的private方法会隐式的指定为final方法

final还可以修饰方法的参数,表示该参数在方法中使用时不可以修改。

这里需要注意的是,final修饰的引用数据类型中其内部数据还是可以被修改的,比如一个final修饰的map,有数据<1,3>,可以被修改为<1,2>,所以并不是线程安全的。需要进行解决。

Collections.unmodifiableXXX 系列方法,可以解决上述问题,它可以将输入的引用对象变为不可变对象,内部也是不可变的

Guava:ImmutableXXX系列方法也可以达到相同的效果

2 线程封闭

把对象封装到一个线程中,只有这一个线程可以看到这个对象,那么这个对象就不用考虑线程安全问题。

下面用例子演示ThreadLocal的使用:

参考博客:面试官再问你 ThreadLocal,你就这样“怼”回去!

  ThreadLocal实现里使用Map来保存的,Key保存线程id,value保存数据。

  假设一个常见的用法,也就是前端往后端传递数据,比如一个用户数据,可能需要从Controller传到Service甚至传到Dao层,多次传递容易出现问题。我们可以利用ThreadLocal + Filter的方式,将数据在交给Controller处理前就保存下来,需要使用的时候进行获取,使用完释放。具体代码:

首先是保存有ThreadLocal的一个类,用以数据的添加、获取和移除

public class RequestHolder {
private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();
// 保存数据
public static void add(Long id) {
requestHolder.set(id);
} // 获取数据
public static Long getId() {
return requestHolder.get();
} // 移除资源
public static void remove() {
requestHolder.remove();
}
}

然后是编写Filter和Inteceptor

@Slf4j
public class HttpFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
log.info("Filter执行,添加线程id:{}到ThreadLocal,请求是{}", Thread.currentThread().getId(), request.getServletPath());
RequestHolder.add(Thread.currentThread().getId());
filterChain.doFilter(servletRequest, servletResponse);
} @Override
public void destroy() { }
}
public class HttpInteceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("preHandle执行");
return true;
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion执行");
RequestHolder.remove();
return;
}
}

注册Filter和Inteceptor

@SpringBootApplication
public class ConcurrencyApplication extends WebMvcConfigurerAdapter { public static void main(String[] args) {
SpringApplication.run(ConcurrencyApplication.class, args);
} /**
* 将自己实现的Filter进行注册
* 需要添加Filter实现类,对应url等信息
* @return
*/
@Bean
public FilterRegistrationBean httpFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
// 添加实现类
filterRegistrationBean.setFilter(new HttpFilter());
// 添加url
filterRegistrationBean.addUrlPatterns("/threadLocal/*");
return filterRegistrationBean;
} @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HttpInteceptor()).addPathPatterns("/**");
}
}

最后编写测试所用Controller

@RestController
@RequestMapping("/threadLocal")
public class ThreadLocalController { @RequestMapping("/test")
public Long test() {
return RequestHolder.getId();
}
}

3 线程不安全类和写法

一些常见的线程不安全类及其解决方法

1)StringBuilder(线程不安全,单线程推荐使用,效率高) 和 StringBuffer(线程安全,多线程使用)

2)SimpleDateFormat 线程不安全,参考博客:https://blog.csdn.net/csdn_ds/article/details/72984646

使用jodaTime(线程安全)

3)ArrayList、HashSet、HashMap等集合是 线程不安全的

4 同步容器

对集合进行遍历操作是不要做删除操作

5 并发容器 J.U.C

上面提到的同步容器,可以一定程度上保证线程安全,但还是会出现线程不安全的情况,所以出现了并发容器

1)ArrayList ---> J.U.C中的 CopyOnWriteArrayList .该类在更新操作的时候会加锁,然后先复制一份原来的List,再添加元素,然后重新赋值回原来的。 适合于list元素少,读多于写

2)

3)

Java并发--线程安全策略的更多相关文章

  1. Java高并发--线程安全策略

    Java高并发--线程安全策略 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 不可变对象 发布不可变对象可保证线程安全. 实现不可变对象有哪些要注意的地方?比如JDK ...

  2. Java 并发 线程同步

    Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...

  3. Java 并发 线程的优先级

    Java 并发 线程的优先级 @author ixenos 低优先级线程的执行时刻 1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止.退出或者由于 ...

  4. Java 并发 线程属性

    Java 并发 线程属性 @author ixenos 线程优先级 1.每当线程调度器有机会选择新线程时,首先选择具有较高优先级的线程 2.默认情况下,一个线程继承它的父线程的优先级 当在一个运行的线 ...

  5. Java 并发 线程的生命周期

    Java 并发 线程的生命周期 @author ixenos 线程的生命周期 线程状态: a)     New 新建 b)     Runnable 可运行 c)     Running 运行 (调用 ...

  6. Java并发——线程安全、线程同步、线程通信

    线程安全 进程间"共享"对象 多个“写”线程同时访问对象. 例:Timer实例的num成员,即add()方法是用的次数.即Timer实例是资源对象. class TestSync ...

  7. 从JDK源码角度看java并发线程的中断

    线程的定义给我们提供了并发执行多个任务的方式,大多数情况下我们会让每个任务都自行执行结束,这样能保证事务的一致性,但是有时我们希望在任务执行中取消任务,使线程停止.在java中要让线程安全.快速.可靠 ...

  8. Java并发——线程介绍

    前言: 互联网时代已经发展到了现在.从以前只考虑小流量到现在不得不去考虑高并发的问题.扯到了高并发的问题就要扯到线程的问题.你是否问过自己,你真正了解线程吗?还是你只知道一些其他博客里写的使用方法.下 ...

  9. java并发线程池---了解ThreadPoolExecutor就够了

    总结:线程池的特点是,在线程的数量=corePoolSize后,仅任务队列满了之后,才会从任务队列中取出一个任务,然后构造一个新的线程,循环往复直到线程数量达到maximumPoolSize执行拒绝策 ...

随机推荐

  1. 【转】Oracle基础结构认知——oracle内存结构 礼记八目 2017-12-15 20:31:27

    oracle的数据库实例是一组后台进程和内存结构组成的,而内存结构由系统全局区(system global area)和程序全局区(program global area)组成. #修改SGA和PGA ...

  2. 何使用ultraiso软碟通制作u盘启动盘(转载)

        现在很多网友都不知道如何用UltraISO软件来制作制作u盘启动盘,那么今天U大师小编就来给大家简单的介绍两种方法,首先第一种方法就是网友要到网上下载一个UltraISO软件,这个网上有很多的 ...

  3. Java解析导入Excel文件后台代码实现

    使用MultipartFile上传Excel文件后端代码实现:(springmvc下的spring-webmvc (MultipartFile )上传) 由于POST一个包含文件上传的Form会以mu ...

  4. python面向对象的三大特性之一多态

    多态 多态的特性是调用不同的子类将会产生不同的行为,而无需明确知道这个子类实际上是什么 说白了就是,不同的对象调用相同的方法,产生不同的行为 例如:s1是字符串类型,w1是列表,两个完全不同的对象,他 ...

  5. 【JavaScript框架封装】公共框架的封装

    /* * @Author: 我爱科技论坛 * @Time: 20180706 * @Desc: 实现一个类似于JQuery功能的框架 // 公共框架 // 种子模块:命名空间.对象扩展.数组化.类型的 ...

  6. django迁移数据库报错解决

    迁移数据库时提示之前的项目中模型未引入 如图 我在创建新的工程时,迁移数据模型时发现出错,错误提示关联模型未被解决,提示的模型是之前项目中定义的,本项目并没有用到.于是在不知道错误原因下,我重装dja ...

  7. FCN图像分割

    一. 图像语义分割 传统的图像分割方法主要包括以下几种: 1)基于边缘检测 2)基于阈值分割 比如直方图,颜色,灰度等 3)水平集方法 这里我们要说的是语义分割,什么是语义分割呢?先来看张图: 将目标 ...

  8. XML概述

    本节要点: 标记语言的定义 XML简介 XML与HTML 比较 XML与数据库比较 XML的特点 XML结构 1          标记语言的定义 “XML.SGML.HTML”中的“ML”(Mark ...

  9. java spring中对properties属性文件加密及其解密

    http://blog.csdn.net/yaerfeng/article/details/26561791

  10. [Beginning SharePoint Designer 2010]探索SharePoint Designer

    本章概要: 1.SharePoint Designer是如何进入到微软的工具集中去的 2.SharePoint Designer的基本特性 3.如何创建SharePoint站点 4.如何打开一个已经存 ...