示例程序1:volatile List 属性多线程操作
import java.util.ArrayList;
import java.util.List;
/**
* 使用volatile关键字使得多个线程操作同一个
* 2个线程,
* 一个线程不断往集合里添加元素
* 一个线程监听集合的元素个数
* 当个数等于某个数值时停止此线程
* while(true)监听,性能不好,待改进
* @author Administrator
*
*/
public class ListAdd01 {
/*volatile关键字修饰下才能在多个线程之间共享成员变量,要不然每个线程的方法体中都是当前成员变量的一个副本(在方法体中)*/
private static volatile List<String> list = new ArrayList<String>();
public void add() {
list.add("bjsxt");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final ListAdd01 list1 = new ListAdd01();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for(int i = 0; i < 10; i++) {
list1.add();
System.out.println("当前线程:"+ Thread.currentThread().getName() + "添加了一个元素...");
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
/*以这样的方式在这里等待需要消耗太多的系统资源,不推荐*/
while(true) {
if(list1.size() == 5) {
System.out.println("当前线程:"+ Thread.currentThread().getName() + "收到了一个通知,listSize = 5线程停止...");
throw new RuntimeException();
}
}
}
},"t2");
t1.start();
t2.start();
}
}
示例程序2: 一线程监听,被唤醒,触发用计数器要优于wait,notify,因为notify不释放锁
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* wait、notify方法,wait释放锁,notify不释放锁
*
*
* 采用wait,notify的输出结果
t2进入...
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
已经发出通知:notify
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t1 添加了一个元素
当前线程:t2收到了一个通知,listSize = 5线程停止...
Exception in thread "t2" java.lang.RuntimeException
at com.bjsxt.thread.ListAdd02$2.run(ListAdd02.java:62)
at java.lang.Thread.run(Thread.java:745)
直到最后一刻才输出,所以这种方式无法及时被执行
那怎么办呢?
用CountDownLatch:计数器,是一个阻塞flag,和同步不同步没关系,和锁没有任何关系
多用于远程链接的实现,比如zookeeper客户端调用远程连接(举得小例子)
*
*/
public class ListAdd02 {
public volatile List<String> list = new ArrayList<String>();
void add(){
list.add("bjsxt");
}
public int size() {
return list.size();
}
public static void main(String[] args) {
final ListAdd02 list2 = new ListAdd02();
//实例化一个lock
//当使用wait和notify的时候,一定要配合着synchronized使用
final Object lock = new Object();
final CountDownLatch count = new CountDownLatch(1);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
//不要放到for循环外,等到天荒地老啊,若是放到for循环里面就更细粒度了,没问题(待测)。
//若是这里的目的仅仅是保证10次for循环的原子性,那用synchronized完全OK,没问题,
//但若目的是为了通知另外一个进程,并使另外的接到统治的 进程即时处理,则不适宜用synchronized。
// synchronized (lock) {
for(int i = 0; i < 10; i++) {
list2.add();
System.out.println("当前线程:"+ Thread.currentThread().getName() + " 添加了一个元素");
Thread.sleep(500);
if(list2.size() == 5) {
System.out.println("已经发出通知:notify");
//notify虽然通知了,但是并没有释放锁,
//所以lock.wait()那里收到通知了也继续执行了,但因为锁被notify这占据着,所以线程被阻塞了,卡在那了
//只要等到notify()的线程执行完毕释放了锁后,wait()重新获取到了锁后才能继续执行下去,不被卡住
// lock.notify();
count.countDown();
}
}
// }
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1");
/**
* 监听等待,
*/
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
// synchronized (lock) {
if(list2.size() != 5) {
try {
System.out.println("t2进入...");
// lock.wait();//等待并且释放锁
count.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程:"+ Thread.currentThread().getName() + "收到了一个通知,listSize = 5线程停止...");
throw new RuntimeException();
}
// }
}
},"t2");
t2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.start();
}
}
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 我的模拟队列
* @author Administrator
*
*/
public class MyQueue {
//队列
LinkedList<Object> list = new LinkedList<Object>();
//计数器
private AtomicInteger count = new AtomicInteger(0);
//同步锁
private Object lock = new Object();
private final int minSize = 0;
private final int maxSize;
public MyQueue(int maxSize){
this.maxSize = maxSize;
}
public void add(Object obj){
synchronized(lock) {
try {
while(count.get() == maxSize) {
lock.wait();
}
//加入元素
list.add(obj);
//计数器加1
count.incrementAndGet();
//唤醒另外一个线程
lock.notify();
System.out.println("新插入的元素为:" + obj);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public Object take() {
synchronized(lock) {
Object firstInObject = null;
try {
while(count.get() == minSize){
lock.wait();
}
//数量减减
firstInObject = list.removeFirst();
//计数器减1
count.decrementAndGet();
//通知另外一个线程(唤醒)
lock.notify();
System.out.println("拿出的元素为:" + firstInObject);
} catch (InterruptedException e) {
e.printStackTrace();
}
return firstInObject;
}
}
public int size() {
return count.get();
}
public static void main(String[] args) {
final MyQueue queue = new MyQueue(5);
//插入5个元素,已满
queue.add("a");
queue.add("b");
queue.add("c");
queue.add("d");
queue.add("e");
System.out.println("当前容量长度为:" + queue.size());
//再次插入,阻塞
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
queue.add("f");
queue.add("g");
}
},"t1");
t1.start();//t1的执行结果在t2之后,因为已经满了,被阻塞了,
//拿出
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i<3; i++) {
queue.take();
}
}
},"t2");
//隔3秒再拿出
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}