编程题:实现一个容器,提供两个方法,add,size。写两个线程,线程 1 添加 10 个对象到容器中,线程 2 实现监控容器中对象的个数,当个数到 5 个时,线程 2 给出提示并结束。
原因
学习马士兵老师的多线程,看到有这一道面试题。在下面做了一些实验,观测结果。发现线程1如果不加睡眠延时,循环执行的话会出现指令重排的问题。以下是记录,仅供参考,如有错误之处还望大神不吝赐教。
普通方法实现
import java.util.List;
import java.util.concurrent.TimeUnit;
public class MyContainer {
volatile List list = new ArrayList();
public void add(Object o) {
list.add(o);
}
public int size() {
return list.size();
}
public void sleep(int i) {
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
MyContainer container = new MyContainer();
new Thread(() -> {
System.out.println("线程1 start");
for(int i=0;i<10;i++) {
container.add(new Object());
System.out.println("add"+i);
container.sleep(1);
}
System.out.println("线程1 end");
},"线程1").start();
new Thread(()->{
System.out.println("线程2 start");
while(true) {
if(container.size()==5) {
break;
}
}
System.out.println("线程2 end");
},"线程2").start();
}
}
输出结果:
去除睡眠延时,输出结果(这里只是其中一种结果,如需看其他结果可以将上述代码执行查看):
volatile实现
import java.util.List;
import java.util.concurrent.TimeUnit;
public class MyContainer1 {
volatile List list = new ArrayList();
public void add(Object o) {
list.add(o);
}
public int size() {
return list.size();
}
public void sleep(int i) {
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
MyContainer1 container = new MyContainer1();
Object obj = new Object();
Object obj1 = new Object();
while (true) {
Thread t2 = new Thread(() -> {
System.out.println("线程2 start");
synchronized (obj) {
try {
obj.wait();
System.out.println("线程2 end");
obj.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "线程2");
Thread t1 = new Thread(() -> {
System.out.println("线程1 start");
for (int i = 0; i < 10; i++) {
container.add(new Object());
System.out.println("add" + i);
if (container.size() == 5) {
synchronized (obj) {
try {
obj.notify();
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// container.sleep(1);
}
System.out.println("线程1 end");
synchronized (obj1) {
container.list.clear();
obj1.notify();
}
}, "线程1");
t2.start();
t1.start();
synchronized (obj1) {
obj1.wait();
}
}
}
}
输出结果(这里是结果的一段截图):
LockSupport实现
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class MyContainerLockSupport {
volatile List list = new ArrayList();
static Thread t1,t2=null;
public void add(Object o) {
list.add(o);
}
public int size() {
return list.size();
}
public void sleep(int i) {
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
MyContainerLockSupport container = new MyContainerLockSupport();
Object obj = new Object();
Object obj1 = new Object();
while (true) {
t2 = new Thread(() -> {
System.out.println("线程2 start");
LockSupport.park();
System.out.println("线程2 end");
LockSupport.unpark(t1);
}, "t2");
t1 = new Thread(() -> {
System.out.println("线程1 start");
for (int i = 0; i < 10; i++) {
container.add(new Object());
System.out.println("add" + i);
if (container.size() == 5) {
LockSupport.unpark(t2);
LockSupport.park();
}
}
System.out.println("线程1 end");
synchronized (obj1) {
container.list.clear();
obj1.notify();
}
}, "t1");
t2.start();
t1.start();
synchronized (obj1) {
obj1.wait();
}
}
}
}
输出结果正常
上述代码,不加睡眠延时循环执行时,只有用LockSupport的代码能够正常运行,如果遇到此类情况,更偏向于用此种方式。