并发安全

并发安全

线程封闭
ad-hoc 线程封闭

这是完全靠实现者控制的线程封闭,他的线程封闭完全靠实现者实现。ad-hoc 线程封闭非常脆弱,应该尽量避免使用

栈封闭

使用局部变量,方法中的局部变量都会拷贝一份到线程栈中,不会被多个线程共享。

无状态的类

没有任何成员变量,这种类一定是线程安全的

public class StatelessClass {
	public int service(int a,int b){

	    return a+b;
    }

    public void serviceUser(UserVo user){
        //do sth user
    }

}
让类不可变
  1. 加final关键字,但要注意如果成员变量为一个对象时,要保证对象也是不可变的
public class ImmutableClass {
    private final int a;//这里是安全的
    private final UserVo user = new UserVo();//这里是不安全的

	public int getA() {
		return a;
	}

	public UserVo getUser() {
		return user;
	}


	public ImmutableClass(int a) {
		this.a = a;
	}

	public static class User{
    	private int age;

		public int getAge() {
			return age;
		}

		public void setAge(int age) {
			this.age = age;
		}
    }
}
  1. 不提供任何可供修改成员变量的地方,同时成员变量也不作为方法的返回值
public class ImmutableClassToo {
    private List<Integer> list = new ArrayList<>(3);

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

    public boolean isContain(int i){
        return list.contains(i);
    }
}
volatile

并不能保证类的线程安全性,只能保证类的可见性,最适合一个线程写,多个线程读的情景。

加锁和CAS

最常用的手段,使用synchronized和各种显示锁,CAS机制等

安全的发布
  1. 基本类型的发布
public class SafePublish {
	private int i;

    public SafePublish() {
    	i = 2;
    }
	
	public int getI() {
		return i;
	}

	public static void main(String[] args) {
		SafePublish safePublish = new SafePublish();
		int j = safePublish.getI();
		System.out.println("before j="+j);
		j = 3;
		System.out.println("after j="+j);
		System.out.println("getI = "+safePublish.getI());
	}
}
  1. JDK的原生对象
public class SafePublishToo {
    private List<Integer> list
            = Collections.synchronizedList(new ArrayList<>(3));

    public SafePublishToo() {
        list.add(1);
        list.add(2);
        list.add(3);
    }
    public List getList() {
        return list;
    }
    public static void main(String[] args) {
        SafePublishToo safePublishToo = new SafePublishToo();
        List<Integer> list = safePublishToo.getList();
        System.out.println(list);
        list.add(4);
        System.out.println(list);
        System.out.println(safePublishToo.getList());
    }
}
  1. 不安全的发布
public class UnSafePublish {
	private List<Integer> list = new ArrayList<>(3);
	
    public UnSafePublish() {
    	list.add(1);
    	list.add(2);
    	list.add(3);
    }
	public List getList() {
		return list;
	}
	public static void main(String[] args) {
		UnSafePublish unSafePublish = new UnSafePublish();
		List<Integer> list = unSafePublish.getList();
		System.out.println(list);
		list.add(4);
		System.out.println(list);
		System.out.println(unSafePublish.getList());
	}
}
  1. 包装一个类,将内部成员对象进行线程安全的包装
/**
 * @author lizhangbo
 * @title: SoftPublicUser
 * @projectName concurrent
 * @description: 仿Collections对容器的包装,将内部成员对象进行线程安全包装
 * @date 2019/5/15  21:06
 */
public class SoftPublicUser {
    private final UserVo user;

    public UserVo getUser() {
        return user;
    }

    public SoftPublicUser(UserVo user) {
        this.user = user;
    }

    public static class SynUser extends UserVo {
        private final UserVo userVo;
        private final Object lock = new Object();

        public SynUser(UserVo userVo) {
            this.userVo = userVo;
        }

        @Override
        public int getAge() {
            synchronized (lock) {
                return userVo.getAge();
            }
        }

        @Override
        public void setAge(int age) {
            synchronized (lock) {
                userVo.setAge(age);
            }
        }
    }
}

5.委托给线程安全的类来做

/**
 * @author lizhangbo
 * @title: SafePublicFinalUser
 * @projectName concurrent
 * @description: 委托给线程安全的类来做
 * @date 2019/5/15  21:12
 */
public class SafePublicFinalUser {
    private final SynFinalUser user;

    public SynFinalUser getUser() {
        return user;
    }

    public SafePublicFinalUser(FinalUserVo userVo) {
        this.user = new SynFinalUser(userVo);
    }

    private static class SynFinalUser {
        private final FinalUserVo userVo;
        private final Object lock = new Object();

        public SynFinalUser(FinalUserVo userVo) {
            this.userVo = userVo;
        }

        public int getAge() {
            synchronized (lock) {
                return userVo.getAge();
            }
        }

        public void setAge(int age) {
            synchronized (lock) {
                userVo.setAge(age);
            }
        }
    }
}
ThreadLocal

实现线程封闭的最好方法

Servlet辨析

不是线程安全的类
平时感觉不出来是因为:

  1. 在需求上,很少有共享的需求;
  2. 接受请求,返回应答,一般都是有一个线程负责的
    但是只要Sevlet中只要有成员变量,一旦有多线程的写,就有可能产生线程安全问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值