单例和多线程
ThreadLocal概念:线程局部变量,是一个多线程间并发访问变量的解决方案。与其synchronized等加锁的方式不同,ThreadLocal完全不提供锁,而使用空间换时间的手段,为每个线程提供变量的独立副本,以保障线程的安全。
从性能上说,ThreadLocal不具备绝对的优势,在并发不是很高的时候,加锁的性能会更好,但作为一套与锁完全无关的线程安全解决方案,在高并发或者竞争激烈的场景,使用ThreadLocal可以在一定的程度上减少锁竞争。
ThreadLocl的代码案例如下:
public class Test4 {
private ThreadLocal<String> list = new ThreadLocal<String>();
public void setVlaue(String value)
{
list.set(value);
}
public void getValue()
{
System.out.println("当前的线程:"+Thread.currentThread().getName()+";值为:"+list.get());
}
public static void main(String[] args) throws Exception {
Test4 test1 = new Test4();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
test1.setVlaue("a");
test1.getValue();
} catch (Exception e) {
e.printStackTrace();
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
test1.getValue();
} catch (Exception e) {
e.printStackTrace();
}
}
},"t2");
t1.start();
t2.start();
}
}
运行的结果是:
当前的线程:t1;值为:a
当前的线程:t2;值为:null
解释:ThreadLocal完全不提供锁,而使用空间换时间的手段,为每个线程提供变量的独立副本。也就是线程间的ThreadLocal是不可见的,互相不影响的。
单例与多线程
单例模式最常见的就是懒汉式和饿汉式,名字的命名就是依据与创建对象的先后顺序。其中在实际的开发中使用的单例模式有两种:一是静态内部类,二是懒汉式的双重判断。
静态内部类:
public class Test5 {
// 静态内部类
private static class Singletion{
private static Singletion singletion = new Singletion();
}
// 获取实例
public static Singletion getInstance()
{
return Singletion.singletion;
}
}
懒汉式的双重判断(只有一重判断的案例):
public class Test6 {
// 静态内部类
private static Test6 test = null;
public static Test6 getInstance() {
if (test == null) {
try {
// 模拟业务场景
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (Test6.class) {
//if (test == null) {
test = new Test6();
//}
}
}
return test;
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Test6.getInstance().hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Test6.getInstance().hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Test6.getInstance().hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t3");
t1.start();
t2.start();
t3.start();
}
}
输出的结果:
1384277657
1804397488
619028145
懒汉式的双重判断(双重判断的案例):
public class Test6 {
// 静态内部类
private static Test6 test = null;
public static Test6 getInstance() {
if (test == null) {
try {
// 模拟业务场景
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (Test6.class) {
// 这里需要判断非空
if (test == null) {
test = new Test6();
}
}
}
return test;
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try { System.out.println(Test6.getInstance().hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try { System.out.println(Test6.getInstance().hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try { System.out.println(Test6.getInstance().hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t3");
t1.start();
t2.start();
t3.start();
}
}
输出的结果是:
1384277657
1384277657
1384277657