三种方法
题目一
自定义同步容器,容器容量上限为10。可以在多线程中应用,并保证数据线程安全。
方式一:synchronized/wait/notifyAll
public class Test_04<E> {
private LinkedList<E> list = new LinkedList<E>();
private final int MAX_SIZE = 10;
private int count = 0;
public synchronized void put(E e) {
while (list.size() == MAX_SIZE) {
try {
this.wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
list.add(e);
count++;
this.notifyAll();
}
public synchronized E get() {
E e = null;
while (list.size() == 0) {
try {
this.wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
e = list.removeFirst();
count--;
this.notifyAll();
return e;
}
public static void main(String[] args) {
Test_04<Object> m = new Test_04<Object>();
for (int i = 0; i < 2; i++) {
new Thread(() -> {
//容器上限10,25会超出容量限制,会等待
Object object = null;
for (int j = 0; j < 25; j++) {
object = new Object();
m.put(object);
System.out.println(Thread.currentThread().getName() + "-->" + object);
}
}, "p" + i).start();
}
try {
Thread.sleep(400);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//启动10个消费者
for (int i = 0; i < 10; i++) {
new Thread(() -> {
//每次获取5次数据
for (int j = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName() + "-->" + m.get());
}
}, "c" + i).start();
}
}
}
方式二:ReentranLock/await/signalAll
public class Test_05<T> {
private LinkedList<T> list = new LinkedList<T>();
private final int MAX_SIZE = 10;
private int count = 0;
Lock lock = new ReentrantLock();
Condition producer = lock.newCondition();
Condition consumer = lock.newCondition();
/*if导致虚假唤醒状态
用if会出现的问题:假定某一时刻,容器已经生产满了,这时刚好有两个生产者线程先后到达wait那行进入等待,并释放锁,
* 接着有个消费者线程拿走了一个容器内对象,就意味着容器有空闲,又可以往里生产了
* 此时其中一个生产者线程拿到锁对象,从wait处继续往下执行,执行到if括号结尾时另外一个线程也拿到了锁对象,从wait处继续往下执行
* 这个时候问题就出来了,
*/
public void put(T t) {
lock.lock();
try {
while (list.size() == MAX_SIZE) {
producer.await();
}
list.add(t);
count++;
//如果用notify方法,假定当前时刻容器已经满了,本应该唤醒消费者线程进行消费,
//可是不恰巧它唤醒的又是一个生产者,这个生产者进入while循环,执行wait方法,等待
consumer.signalAll();
} catch (Exception e) {
// TODO: handle exception
} finally {
lock.unlock();
}
}
public T get() {
lock.lock();
T res = null;
try {
while (list.size() == 0) {
consumer.await();
}
res = list.removeFirst();
count--;
//借助条件唤醒所有的生产者
producer.signalAll();
} catch (Exception e) {
// TODO: handle exception
} finally {
lock.unlock();
}
return res;
}
public static void main(String[] args) {
Test_05<Object> m = new Test_05<Object>();
//此处跟上面一样...
}
}
题目二
自定义容器,提供新增元素和获取元素数量方法,启动两个线程,线程1向容器中新增10个数据,线程2监听容器原色数量,当容器数量为5时,线程2输出信息并终止。
先自定义个容器吧:
class MyContain01{
private List<Object> list = new ArrayList<>();
public void add(Object object){
list.add(object);
}
public int getSize(){
return list.size();
}
}
方法一:volatile 实现, list 变量要加 volatile 关键字
public class Test_03 {
public static void main(String[] args) {
MyContain01 m = new MyContain01();
new Thread(()->{
while (true){//用了死循环太耗费CPU性能了,所以不推荐这种方法
if (m.getSize() == 5 ){
System.out.println("容器大小为 5");
break;
}
}
}).start();
new Thread(()->{
Object object;
for (int i=0; i<10; i++){
object = new Object();
m.add(object);
System.out.println("add contain>>>"+object);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
方法二:生产者消费者 synchronized/wait/notifyAll
public class Test_01 {
public static void main(String[] args) {
MyContain01 m = new MyContain01();
Object lock = new Object();
new Thread(()->{
synchronized (lock){
if (m.getSize()!=5){
try {
lock.wait();//一开始执行到这里暂停直到另一个线程调用了notifyAll方法将其唤醒了
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("容器中数量为 :"+m.getSize());
lock.notifyAll();//调用notify方法唤醒另一个因调用wait陷入等待的线程,如果不调用程序一直等
}
},"t1 ").start();
new Thread(()->{
synchronized (lock){
Object object ;
for (int i=0; i<10; i++){
object = new Object();
System.out.println("add contain>>>"+object);
m.add(object);
if (m.getSize() == 5){
lock.notifyAll();//notify并不会释放锁,此处的notify和wait不能互换
try {
lock.wait();//所以调用wait方法释放锁并停在这里
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
},"t2 ").start();
}
}
方法三:CountDownLatch
public class Test_02 {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(5);
MyContain01 m = new MyContain01();
new Thread(()->{
if (m.getSize() != 5){
try {
latch.await();//停在这里等待门闩开放
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("容器此时的大小为:"+m.getSize());
}).start();
new Thread(()->{
Object object;
for (int i=0; i<10; i++){
object = new Object();
if (latch.getCount() != 0){
latch.countDown();
}
m.add(object);
System.out.println("add contain>>>"+object);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
https://github.com/hfpp2012/hello-umi-block-plugin