0%

AQS

但凡了解多线程的对于AQS应该都有所耳闻吧(我第一次知道AQS还是在一次面试中,那次被虐的老惨了),AQS即AbstractQueuedSynchronizer队列同步器,是一个抽象类,它是从java5开始的同步组件的基础框架,它仅仅只是定义了FIFO同步队列、同步状态的获取和释放方法,很多同步类都继承该类来实现同步逻辑,子类通过继承AQS并实现它的抽象方法来管理同步状态

是构建其他同步组件的基础框架(如ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch等)

阅读全文 »

线程通信

除了使用synchronized来对代码块和方法进行同步外,jdk1.5之后还有一种Lock同步锁的方式进行同步
使用lock.lock()来进行加锁,使用lock.unlock()方法来释放锁
既然可以使用lock来代替synchronized,那么如何进行实现synchronized与wait()、notify()、notifyAll()的线程通信机制呢
在使用lock时使用Condition来进行线程通信

阅读全文 »

synchronized关键字

synchronized作为java的一个关键字,用来保证同一时刻最多只有一个线程执行synchronized修饰的方法/代码块,保证线程安全,解决多线程并发问题。悲观锁

被认定为是悲观锁的原因是并发策略是悲观的,不管是否会产生竞争,任何数据操作都必须要加锁,当然后续的JVM的升级使得synchronized也有了锁升级的过程

作用

  • 保证原子性,由于同一时刻只能有一个线程能够执行临界区的代码,使得临界区的代码是一个原子操作
  • 保证可见性
阅读全文 »

可见性之volatile关键字

什么是可见性

cpu在执行代码的时候,为了减少变量访问的时间消耗可能会将代码中访问的变量值缓存到该CPU的缓存区,所以在相应代码再次访问某个变量时,读到的值可能来自于缓存区而不是主存,同样,代码对这些缓存过的变量值的修改也可能只是被写入到缓存区,而没有回写到主存,且每个CPU都有自己的缓存区,因此一个CPU缓存区中的内容对于其他CPU是不可见的

可见性就是一个线程对于共享变量的修改能够及时的被其他线程看到

共享变量是指如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量

在java规范中指出:为了获得更快的速度,允许线程保存共享变量的私有拷贝,而且只有在线程进入或者离开同步代码块时才会将私有拷贝与共享内存中的原始值进行比较

可见性的实现方式

  • synchronized(保证原子性和可见性) synchronized关键字
  • volatile(只保证可见性),如果变量已在synchronized代码块中,或者为常量时,没有必要使用volatile修饰,比synchronized更快,不会引起线程上下文的切换和调度

先举一个例子,来看一下不使用volatile的时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class TestVolatile {

public static void main(String[] args) {
ThreadDemo runnable = new ThreadDemo();
new Thread(runnable).start();

while (true){
// 不会停止 一直在while循环
if(runnable.isFlag()){
System.out.println("----------");
break;
}
}
}

}

class ThreadDemo implements Runnable{

private boolean flag;
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;

System.out.println(Thread.currentThread().getName()+"---flag:"+flag);
}

public boolean isFlag() {
return flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}
}
阅读全文 »