volatile关键字
volatile关键字的两大作用
1.保证内存、线程间可见
面试题:
实现一个容器,提供两个方法,add、size。 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数数到5个时,线程2给出提示并结束
public class TestOne {
//volatile保证线程间可见,使t2能够得到通知
// volatile List list = new ArrayList();
//synchronizedList保证线程同步
volatile List list = Collections.synchronizedList(new LinkedList<>());
public void add(Object o){
list.add(o);
}
public int size(){
return list.size();
}
public static void main(String[] args) {
TestOne to = new TestOne();
new Thread(()->{
for (int i=0;i<10;i++){
Object o = new Object();
to.add(o);
System.out.println("add"+i);
// try {
// TimeUnit.SECONDS.sleep(1);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
},"t1").start();
new Thread(()->{
while(true){
if (to.size()==5) {
System.out.println("到5了");
break;
}
}
System.out.println("t2结束");
},"t2").start();
}
}
- 分析:
假如不加volatile关键字线程间不可见,while(true)中的方法永远监测不到,会一直循环运行下去。volatile修饰引用值,引用对象指向另外一个new出来的对象,如果这个对象成员变量里面的值改变了,是观察不到的,所以以上代码不合适。
可以利用synchronized锁的wait()、notify()来实现
public class TestOne {
//volatile保证线程间可见,使t2能够得到通知
volatile List list = new ArrayList();
//synchronizedList保证线程同步
// volatile List list = Collections.synchronizedList(new LinkedList<>());
public void add(Object o){
list.add(o);
}
public int size(){
return list.size();
}
public static void main(String[] args) {
TestOne to = new TestOne();
Object lock = new Object();
new Thread(()-> {
synchronized (lock) {
System.out.println("t2启动");
if (to.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("到5了 t2结束");
lock.notify();
}
},"t2").start();
new Thread(()->{
synchronized (lock){
System.out.println("t1启动");
for (int i=0;i<10;i++){
Object o = new Object();
to.add(o);
System.out.println("add"+i);
if (to.size()==5){
lock.notify(); //notify()不释放锁 使得t2拿不到lock 一直处于等待状态
try {
lock.wait(); //利用wait()将锁释放 t2成功拿到锁 继续执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
},"t1").start();
}
}