synchronized同步方式
这里可能有的朋友会觉得在上述例子中我们完全可以通过加锁来实现这个功能。我们首先来看一下用synchronized代码块实现的效果:
package com.jd.rdc.pp.soa.service;
/**
* 需求:线程隔离
* 在多线程并发的场景下,每个线程中的变量都是相互独立
* 线程A:设置(变量1) 获取(变量1)
* 线程B:设置(变量2) 获取(变量2)
* <p>
* ThreadLocal :
* 1、set():将变量绑定到当前线程中
* 2、get():获取当前线程绑定的变量
*/
public class MyDemo1 {
ThreadLocal<String> t1 = new ThreadLocal<>();
//变量
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
//变量content绑定到当前线程他
}
public static void main(String[] args) {
MyDemo1 demo = new MyDemo1();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
/*
* 每个线程:存一个变量,过一会取出这个变量
*/
synchronized (MyDemo1.class) {
demo.setContent(Thread.currentThread().getName() + "的数据");
System.out.println("-----------------------");
System.out.println((Thread.currentThread().getName() + "----->" + demo.getContent()));
}
}
});
thread.setName("线程" + i);
thread.start();
}
}
}
打印结果:
-----------------------
线程0----->线程0的数据
-----------------------
线程1----->线程1的数据
-----------------------
线程2----->线程2的数据
-----------------------
线程3----->线程3的数据
-----------------------
线程4----->线程4的数据
结果可以发现,加锁确实可以解决这个问题,但是在这里我们强调的是线程数据隔离的问题,并不是多线程共享数据的问题,在这个案例中使用synchronized关键字是不合适的。
ThreadLocal与synchronized的区别
虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题,不过两者处理问题的角度和思路不同。
synchronized | ThreadLocal | |
原理 | 同步机制采用 以时间换空间 的方式,只提供了一份变量,让不同的线程排队访问 | ThreadLocal采用 以空间换时间 的方式,为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰 |
侧重点 | 多个线程之间访问资源的同步 | 多线程中让每个线程之间的数据相互隔离 |
总结:在刚刚的案例中,虽然使用ThreadLocal和synchronized都能解决问题,但是使用ThreadLocal更为合适,因为这样可以使程序拥有更高的并发性能。