一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
- 线程处理由于一些数据的操作非原子性的,这样对于在使用多线程的时候会造成数据的错乱,也就失去了对多线程使用的意义。
- 所以说明下线程同步的一些方法
1.多线程有问题的例子
2.为了解决上面个的问题我们可以进行那些操作
2.1加锁
2.1.1锁 synchronized
Synchronized的升级顺序是 无锁–>偏向锁–>轻量级锁–>重量级锁,顺内不可逆
使用很简单写在非静态方法上锁的对象为this
写在静态方法中的时候锁的对象为当前的类
- 同一个对象写在非静态方法上
- 不同对象写在静态方法上
- 每次获取到锁的线程执行完,才能让下个获取锁的线程执行,每次执行是同步的
写在代码块中注意锁的对象 synchronized(obj){}和方法的静态非静态一样
2.1.2锁 lock
lock锁获取和释放时手工的,所以用的时候注意在finally中释放锁
private static int money = 0;
Lock lock=new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
lock.lock();
money++;
lock.unlock();
}
System.out.println("处理后金额:" + money);
}
lock锁的一些方法
| 方法名称 | 描述 |
|---|---|
| void lock() | 获得锁。如果锁不可用,则当前线程将被禁用以进行线程调度,并处于休眠状态,直到获取锁。 |
| void lockInterruptibly() | 获取锁,如果可用并立即返回。如果锁不可用,那么当前线程将被禁用以进行线程调度,并且处于休眠状态,和lock()方法不同的是在锁的获取中可以中断当前线程(相应中断)。 |
| Condition newCondition() | 获取等待通知组件,该组件和当前的锁绑定,当前线程只有获得了锁,才能调用该组件的wait()方法,而调用后,当前线程将释放锁。 |
| boolean tryLock() | 只有在调用时才可以获得锁。如果可用,则获取锁定,并立即返回值为true;如果锁不可用,则此方法将立即返回值为false 。 |
| boolean tryLock(long time, TimeUnit unit) | 超时获取锁,当前线程在一下三种情况下会返回: 1. 当前线程在超时时间内获得了锁;2.当前线程在超时时间内被中断;3.超时时间结束,返回false. |
| void unlock() | 释放锁。 |
lockInterruptibly() 通过这个方法获取锁的时候,是可以相应中断的。但是一旦获取了锁之后是不会相应中断的,因为interrupt()方法只能中断阻塞过程中的线程而不能中断正在运行过程中的线程。Synchronized只有获取到锁之后才能中断,等待锁时不可中断
2.1.3锁 ReadWriteLock锁
//返回用于读取操作的锁
Lock readLock()
//返回用于写入操作的锁
Lock writeLock()
ReadWriteLock lock = new ReentrantReadWriteLock();
lock.readLock().lock();
lock.readLock().unlock();
lock.writeLock().lock();
lock.writeLock().unlock();
ReentrantLock 是互斥锁。
ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作;多个度之间不是互斥的,但是写和读是互斥的,写合写之间是互斥的;只要没有 writer,读取锁可以由多个 reader 线程同时保持,而写入锁是独占的。
2.2 synchronized和lock的区别
-
synchronized是关键字当有异常抛出时系统会自动释放锁,
lock是个接口 释放锁需要手动,需要放在finally{}
-
synchronized是非公平的,
lock可以设置公平和非公平 默认是非公平的
-
synchronized和lock都是可重入锁(就是获取当前的锁,调用别的地方也需要锁这个锁的类型一致可直接获取锁操作)
-
synchronized响应中断的时候需要调方法 Thread.currentThread().isInterrupted()去判断,但是在阻 塞获取锁的时候是无法中断的
lock的tryLock和lockInterruptibly可以相应中断的
-
synchronized中如果执行比较久的话,其他线程会一直在阻塞等待中;
lock的话可以使用tryLock和lockInterruptibly 采取中断或者到时间后自动退出;
-
在读写的时候synchronized是排他锁,每个请求都必须获取到锁;
ReadWriteLock锁可以把读写分离出来,如果都是读的情况可以同时获取锁提高效率
2.3采用原子性变量
private AtomicBoolean isTrue;
private AtomicInteger num;
private AtomicLong numLong;
private AtomicReference reference;
2.2.1 AtomicReference
public class PeoperEntity {
private String name;
private String sex;
public PeoperEntity(String name,String sex) {
this.name=name;
this.sex=sex;
}
}
public static void main(String[] args) {
PeoperEntity p1=new PeoperEntity("张三","1");
PeoperEntity p2=new PeoperEntity("李四","2");
PeoperEntity p3=new PeoperEntity("王五","3");
AtomicReference<PeoperEntity> atomicReference = new AtomicReference<>();
atomicReference.set(p1);
//如果当前值是p1则修改为p2
atomicReference.compareAndSet(p1, p2);
System.out.println(atomicReference.get());
//如果当前值是p1则修改为p3 因为p1变成了p2所以结果为p2
atomicReference.compareAndSet(p1, p3);
System.out.println(atomicReference.get());
}
PeoperEntity [name=李四, sex=2]
PeoperEntity [name=李四, sex=2]