使用synchronized关键字
synchronized是最简单和最常用的一种同步方法,只需要使用synchronized进行包裹,就可以实现代码块实现线程同步。synchronized可以修饰:类、变量,方法,静态变量,静态方法,代码块。
使用锁
java.util.concurrent.locks定义了多种锁,其中ReentrantLock,ReentrantReadWriteLock比较常用。锁需要主动的添加lock和unloock,如果lock以后没有正确的unlock(忘记unlock,被异常跳过等)则会导致死锁。所以在使用锁的时候一定要记得使用unlock,并且lock以后会存在抛出异常的情况,最好把unlock写在finally代码块中。
synchronized和锁的区别:
synchronized是关键字,而锁都是具体的类。
synchronized直接包裹代码快,不会出现忘记释放锁的情况。锁需要自己管理lock和unlock,可能会出现锁为被正确的释放而导致死锁的情况。
使用特殊域变量(volatile)
java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排它锁单独获得这个变量。java语言提供了volatile,在某些情况下比锁更加方便。如果一个字段被声明或volatile,java线程内存模型确保所有线程看到这个变量值是一致的。
volatile变量修饰符如果使用恰当的话,它比synchronized的使用和执行成本会更低,因为它不会引起线程上下文的切换和调度。
synchronized与volatile实现同步的区别:
synchronized是一个重量级的同步功能,会切换上下文。volatile是一个轻量级的同步功能,无需进行上下文的切换。
synchronized需要在不同线程中争抢同一个锁,会出现死锁的情况,而volatile则不需要进行争抢,也不会出现死锁的情况。
直接使用线程安全的基础类
java.util.concurrent包中定义了许多具有线程安全的类,如:ConcurrentHashMap等。在多线程环境可以直接使用这些类,而不需要自己处理线程同步相关的内容。
java.util.concurrent.atomic包中定义了许多具有原子性质的类型,它们的各种操作都具有原子性,所以在多线程中也可以放心大胆的使用。
使用线程局部变量来定义Runnable中的不需要共享的变量
每一个ThreadLocal能够放一个线程级别的变量,可是它本身能够被多个线程共享使用,并且又能够达到线程安全的目的,这是因为单的认为不同线程中get到的对象是不一样的)。