淘宝面试题:
实现一个容器,提供两个方法,add,size
写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
-------------------------------------------------------------------------------------------------------
1.一般写法
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 错误写法
* @author x1c
*
*/
public class MyContainer1 {
List<Object> lists = new ArrayList<>();
public void add(Object obj) {
lists.add(obj);
}
public int getSize() {
return lists.size();
}
public static void main(String[] args) {
MyContainer1 c = new MyContainer1();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add:" + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1结束");
},"t1").start();
new Thread(()->{
while(true) {
if (c.getSize() == 5) {
break;
}
}
System.out.println("t2结束");
},"t2") .start();
}
}
2.给lists添加volatile,t2可以能够接到通知,但是t2线程死循环很浪费cpu
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 加volatile关键字
* @author x1c
*
*/
public class MyContainer2 {
volatile List<Object> lists = new ArrayList<>(); //加入volatile关键字
public void add(Object obj) {
lists.add(obj);
}
public int getSize() {
return lists.size();
}
public static void main(String[] args) {
MyContainer2 c = new MyContainer2();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add:" + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1结束");
},"t1").start();
new Thread(()->{
while(true) {
if (c.getSize() == 5) {
break;
}
}
System.out.println("t2结束");
},"t2") .start();
}
}
3.使用wait和notify,wait会释放锁,而notify不会释放锁 面试
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 锁对象的wait和notify方法: wait释放锁和notify不会释放锁
*
* 锁定哪个对象就用哪个对象来执行notify(), notifyAll(),wait(), wait(long), wait(long, int)操作,
* 否则就会报IllegalMonitorStateException异常
* @author x1c
*
*/
public class MyContainer3 {
volatile List<Object> lists = new ArrayList<>();
public void add(Object obj) {
lists.add(obj);
}
public int getSize() {
return lists.size();
}
public static void main(String[] args) {
MyContainer3 c = new MyContainer3();
final Object lock = new Object();
new Thread(()->{
System.out.println("t2执行");
synchronized (lock) {
if (c.getSize() != 5) {
try {
lock.wait(); //当前线程等待 释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2结束");
lock.notify(); //唤醒等待的其他线程 操作线程结束 锁释放
}
},"t2").start();
new Thread(()-> {
synchronized(lock) {
System.out.println("t1执行");
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add:" + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (c.getSize() == 5) {
lock.notify(); //唤醒当前锁对象的等待线程 注意:不释放锁!!
try {
lock.wait(); //当前线程等待 释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("t1结束");
}
},"t1").start();
}
}
4.用CountdownLatch是较好的选择,
使用Latch(门闩) 替代wait notify来进行通知
好处时通信方式简单,同时也可以指定等待时间
使用await和countdown方法代替wait和notify
CountdownLatch不涉及锁定,当count的值为零时当前线程继续运行
当不涉及同步,只是线程线程通信时,用synchronized+wait+notify显得太重了
应该考虑用countdownlatch /cylicbarrier /semaphore
例子如下
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* 使用Latch(门闩) 替代wait notify来进行通知
* 好处时通信方式简单,同时也可以指定等待时间
* 使用await和countdown方法代替wait和notify
* CountdownLatch不涉及锁定,当count的值为零时当前线程继续运行
* 当不涉及同步,只是线程线程通信时,用synchronized+wait+notify显得太重了
* 应该考虑用countdownlatch /cylicbarrier /semaphore
* @author x1c
*
*/
public class MyContainer4 {
volatile List<Object> lists = new ArrayList<>();
public void add(Object obj) {
lists.add(obj);
}
public int getSize() {
return lists.size();
}
public static void main(String[] args) {
MyContainer4 c = new MyContainer4();
CountDownLatch latch = new CountDownLatch(1); //countdownLatch不涉及锁定,当count为零时当前线程继续执行
new Thread(()->{
System.out.println("t2执行");
if (c.getSize() != 5) {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2结束");
},"t2").start();
new Thread(()-> {
System.out.println("t1执行");
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add:" + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (c.getSize() == 5) {
latch.countDown();
}
}
System.out.println("t1结束");
},"t1").start();
}
}
------------------------------------------EOF--------------------------------------------