您的位置:首页 > 其它

线程安全

2018-03-13 10:01 141 查看
线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。

机制:

1、synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区”。出现异常会释放锁。

关键字Synchronized拥有锁重入的功能,也就是在使用Synchronized的时候,当一个线程得到一个对象的锁后,在该锁里执行代码的时候可以再次请求该对象的锁时可以再次得到该对象的锁。

一个简单的例子就是:在一个Synchronized修饰的方法或代码块的内部调用本类的其他Synchronized修饰的方法或代码块时,是永远可以得到锁的。

Synchronized拥有锁重入的功能主要作用是:避免死锁。

2、用static修改的方法或者变量,在该类的所有对象是具有相同的引用

3、volatile,volatile关键字在这里的含义就是禁止指令的重排序优化,volatile关键字的作用就是强制从公共堆栈中取得变量的值,而不是线程私有的数据栈中取得变量的值。

volatile与synchronized的区别

(1)关键字volatile是线程同步的轻量级实现,性能比synchronized要好,并且volatile只能修于变量,而synchronized可以修饰方法,代码块等。

(2)多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。

(3)volatile可以保证数据的可见性,但不可以保证原子性,而synchronized可以保证原子性,也可以间接保证可见性,因为他会将私有内存和公共内存中的数据做同步。

(4)volatile解决 的是变量在多个线程之间的可见性,而synchronized解决的是多个线程之间访问资源的同步性。

4、Lock接口,其实现类常用的有ReentrantLock,ReentrantLock类能够实现线程同步,并且在此基础上还扩展了很多实用的功能,比使用synchronized更佳的灵活。

实现方式是:在临界区前后使用lock对象的获取锁和释放锁方法。

Lock lock = new ReentrantLock();
//使用:
lock.lock();//获取锁
临界区代码
lock.unlock();//释放锁


synchronizedwait()方法和notify()方式结合实现线程间通信,也就是等待/通知模式。

在ReentrantLock中,是借助Condition对象进行实现的。

Condition condition = lock.newCondition();


(1)Object的wait()方法相当于Condition类中的await()方法;

(2)Object的notify()方法相当于Condition类中的signal()方法;

(3)Object的notifyAll()方法相当于Condition类中的signalAll()方法;

5、类似于我们集合中有同步类容器 和 并发类容器,HashMap也是完全排他的,即使是读也只能同步执行,而ConcurrentHashMap就可以实现同一时刻多个线程之间并发。为了提高效率,ReentrantLock的升级版ReentrantReadWriteLock就可以实现效率的提升

ReentrantReadWriteLock有两个锁:一个是与读相关的锁,称为“共享锁”;另一个是与写相关的锁,称为“排它锁”。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。

方法:

ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
//使用读锁:
lock.readLock().lock();
lock.readLock().unlock();
//使用写锁
lock.writeLock().lock();
lock.writeLock().unlock();


5、计数器CountDownLatch和循环屏障CyclicBarrier

CountDownLatch countDownLatch = new CountDownLatch(ThreadNumber);//ThreadNumber为线程数
//每个线程执行后都要执行下面的这个方法:
countDownLatch.countDown(); //把计数器减1
最后在主线程执行:
countDownLatch.await();//等待所有线程执行完成,即计数器为0之后再继续执行。


CyclicBarrier cb = new CyclicBarrier(num);
//num为thread数量
//CyclicBarrier是另一种多线程并发控制使用工具,和CountDownLatch非常类似,他也可以实现线程间的计数等待,但他的功能要比CountDownLatch更加强大一些。
//CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
//CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。


CyclicBarrier和CountDownLatch的区别

(1)CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。

(2)CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。

(3)CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程安全