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]