类的线程安全定义  

如果多线程下使用这个类,不过多线程如何使用和调度这个类,这个类总是表示出正确的行为,这个类就是线程安全的。

类的线程安全表现为:

  1. 操作的原子性
  2. 内存的可见性

不做正确的同步,在多个线程之间共享状态的时候,就会出现线程不安全。

怎么才能做到类的线程安全?

栈封闭

所有的变量都是在方法内部声明的,这些变量都处于栈封闭状态。

无状态

没有任何成员变量的类,就叫无状态的类

package com.caojiulu;

/**
*
*@author caojiulu
*
*类说明:无状态的类,没有任何的成员变量
*/
public class StatelessClass {

public int service(int a,int b) {
return a*b;
}


}

让类不可变

让状态不可变,两种方式:

1,加final关键字,对于一个类,所有的成员变量应该是私有的,同样的只要有可能,所有的成员变量应该加上final关键字,但是加上final,要注意如果成员变量又是一个对象时,这个对象所对应的类也要是不可变,才能保证整个类是不可变的。

示例代码:

package com.caojiulu;


/**
*@author caojiulu
*
*类说明:看起来不可变的类,实际是可变的
*/
public class ImmutableFinalRef {

private final int a;
private final int b;
private final User user;//这里,就不能保证线程安全啦

public ImmutableFinalRef(int a, int b) {
super();
this.a = a;
this.b = b;
this.user = new User(2);
}

public int getA() {
return a;
}

public int getB() {
return b;
}

public User getUser() {
return user;
}

public static class User{
private int age;

public User(int age) {
super();
this.age = age;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

}

public static void main(String[] args) {
ImmutableFinalRef ref = new ImmutableFinalRef(12,23);
User u = ref.getUser();
u.setAge(35);
}
}

2、根本就不提供任何可供修改成员变量的地方,同时成员变量也不作为方法的返回值

volatile

保证类的可见性,最适合一个线程写,多个线程读的情景,

加锁和CAS

 

安全的发布

类中持有的成员变量,特别是对象的引用,如果这个成员对象不是线程安全的,通过get等方法发布出去,会造成这个成员对象本身持有的数据在多线程下不正确的修改,从而造成整个类线程不安全的问题。

package com.caojiulu;

import java.util.ArrayList;
import java.util.List;

/**
*@author caojiulu
*
*类说明:存在着不安全的发布
*/
public class UnsafePublish {
//要么用线程的容器替换
//要么发布出去的时候,提供副本,深度拷贝
private List<Integer> list = new ArrayList<>(3);

public UnsafePublish() {
list.add(1);
list.add(2);
list.add(3);
}

//讲list不安全的发布出去了
public List<Integer> getList() {
return list;
}

//也是安全的,加了锁--------------------------------
public synchronized int getList(int index) {
return list.get(index);
}

public synchronized void set(int index,int val) {
list.set(index,val);
}

}

TheadLocal

ThreadLocal的实例代表了一个线程局部的变量,每条线程都只能看到自己的值,并不会意识到其它的线程中也存在该变量。

它采用采用空间来换取时间的方式,解决多线程中相同变量的访问冲突问题。