博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发--线程安全策略
阅读量:6599 次
发布时间:2019-06-24

本文共 3793 字,大约阅读时间需要 12 分钟。

 

 

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实现里使用Map来保存的,Key保存线程id,value保存数据。

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

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

public class RequestHolder {    private final static ThreadLocal
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

@Slf4jpublic 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

@SpringBootApplicationpublic 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 线程不安全,参考博客:

使用jodaTime(线程安全)

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

4 同步容器

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

5 并发容器 J.U.C

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

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

2)

3)

 

 

转载于:https://www.cnblogs.com/panlei3707/p/11065780.html

你可能感兴趣的文章
ubuntu 下安装 matplotlib
查看>>
编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字......
查看>>
050:navie时间和aware时间详解
查看>>
百度地图车辆运动轨迹
查看>>
使用ReaderWriterLock类实现多用户读/单用户写同步
查看>>
JSP页面重定向
查看>>
DroidCam 一片 红色 解决办法
查看>>
用 Hexo + Next + GitHubPages 搭建漂亮的免费博客
查看>>
Pandas:按条件进行行选择
查看>>
spring boot 自定义规则访问获取内部或者外部静态资源图片
查看>>
springmvc + mybatis + ehcache + redis架构
查看>>
sed指定行范围匹配(转贴!)
查看>>
C#语音朗读文本 — TTS的实现
查看>>
Python正则表达式初识(十)附正则表达式总结
查看>>
APICLOUD 1.1.0 开发环境搭建
查看>>
《Cadence 16.6电路设计与仿真从入门到精通》——导读
查看>>
Confluence 6 如何让我的小组成员知道那些内容是重要的
查看>>
找到一个适合的分布式文件系统之各种分布式文件系统优缺点对比
查看>>
httpd基本配置
查看>>
索引失效的几个原因
查看>>