示例程序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();
}
}