1. 同步的方式
总所周知,我们平常所用的同步方式:① synchronized关键字 ② Lock
这是一段未被同步的代码,i的值一般不会为10000。这是因为每段线程的都有各自的工作的内存,并且i++不是为原子操作,它们修改i的值的步骤分为三步:读入数据,修改,写入主内存。它们也并不会是井井有序的一个一个的来,而是一拥而上,多个线程读取可以为同一个数值,这样会造成该线程做无用功。So,我们的方法就是让它们一个一个来。
public class test1 implements Runnable{
private int i=0;
public void increase() {
i++;
}
public static void main(String[] args) throws InterruptedException {
Runnable r = new test1();
for(int i=0;i<10000;i++) {
Thread t = new Thread(r);
t.start();
}
}
@Override
public void run() {
increase();
System.out.println(Thread.currentThread().getName()+"--"+i);
}
}
synchroni和Lock都是属于重入锁。
重入锁:每个对象都具有各自的对象锁,一个线程在已经获取对象锁时,可以再次的获取该对象锁。
重入锁的意思:避免死锁。
- synchronized关键字
运用synchronized进行同步的时候需要绑定一个对象锁,不写则默认为this。
synchronized关键字的用法:
- 修饰方法
public synchronized void increase() {
//同步的代码
}
- 修饰代码块
synchronized (对象) {
//同步的代码
}
- 上面的代码的改进方式
public synchronized void increase() {
i++;
}
//或者
public synchronized void increase() {
synchronized (this) {
i++;
}
}
- Lock
Lock为一个接口,实现类为ReentrantLock,ReentrantReadWriteLock。
private Lock lock = new ReentrantLock();
lock.lock();
//之间为需同步的代码块
lock.unlock();
//上面例子修改
public void increase() {
lock.lock();
i++;
lock.unlock();
}
2.它们之间的异同
- 公平锁
公平锁的意思以时间先后顺序来进行运行,两种同步方式默认都为非公平锁,以线程的优先级进行划分,但是Lock可以通过构造方法进行公平锁的构建。 - 可重入
如果锁具备可重入性,则称作为可重入锁。方法一和方法二皆为同步方法,在运行时都需要请求该对象的对象锁。线程需要再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。如果不为重入锁,则会一直等待,知道方法一释放对象锁。
class Test {
public synchronized void method1() {
method2();
}
public synchronized void method2() {
}
}
- 可中断
synchronized同步为不为中断锁,Lock为可以中断锁。Lock可以运用tryLock(),tryLock(time, unit)进行判断该对象锁是否已经被占有,若占有可以进行等待多长时间或者干其他事情。 - 细节
- 锁的释放
synchronized同步方式所持有的锁只能单线程只有,其余线程只能等待,锁由JVM释放。Lock的锁需要自动手动释放,在finally中释放,若没有释放,则会造成死锁。 - 读写锁
对于同一个资源,若线程只进行数据的读取,synchronized同步方式还是会一个一个来,而Lock接口下具有实现类ReentrantReadWriteLock,分为读锁,写锁,读锁为共享锁,写锁为单线程锁。 - 底层区别
Lock是一个接口,而synchronized是Java中的关键字,synchronized的底层实现依靠值JVM。
两者在并发量不大的情况下,相差不大,若并发量较大,则Lock的性能优于synchronized。