目錄
使用wait和notify實現生產者消費者
public class Main2 {
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
int MAX = 5;//生產商品總數
Thread t1 = new Thread(){
public void run(){
while ( true ) {
synchronized (list) {//加鎖
while ( list.size() == MAX ) {
try {
list.wait();//如果生產商品數目大於生產商品最大值,那麼釋放鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int num = (int) (Math.random() * 100);
list.add(num);
System.out.println(Thread.currentThread().getName() + "---" + num);
list.notify();//喚醒消費者線程,只有當前線程釋放鎖後才能被喚醒
}
}
}
};
Thread t2 = new Thread(){
public void run(){
while ( true ) {
synchronized (list) {//加鎖
while ( list.size() == 0 ) {//消費完隊列中商品進行等待
try {
list.wait();//等待釋放鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int num = list.pop();//隊列中有商品,進行消費
System.out.println(Thread.currentThread().getName() + "---" + num);
list.notify();//喚醒生產者線程,只有當前線程釋放鎖後才能被喚醒
}
}
}
};
t1.start();
t2.start();
}
}
使用阻塞隊列來實現生產者消費者模式
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
/**
* Created by Hollake on 2019\8\14 0014 15:31.
*/
public class BlockingQueueTest {
public static void main(String[] args) {
BlockingDeque<Integer> queue = new LinkedBlockingDeque<>(5);
Thread t1 = new Thread(){
public void run(){
while ( true ) {
int temp = (int) (Math.random() * 100);
try {
queue.put(temp);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "----" + temp);
}
}
};
Thread t2 = new Thread(){
public void run(){
while ( true ) {
try {
int res = queue.take();
System.out.println(Thread.currentThread().getName() + "----" + res);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
t2.start();
}
}
兩線程交替打印AB
public class Main2 {
static boolean flag = false;
public static void main(String[] args) {
Object LOCK = new Object();
Thread t1 = new Thread(){
public void run(){
while ( true ) {
synchronized (LOCK) {//加鎖
while ( flag ) {
try {
LOCK.wait();//滿足條件就釋放鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "---" + "A");
flag = true;
LOCK.notify();//喚醒另外一個線程,只有當前線程釋放鎖後才能被喚醒
}
}
}
};
Thread t2 = new Thread(){
public void run(){
while ( true ) {
synchronized (LOCK) {//加鎖
while ( !flag ) {
try {
LOCK.wait();//等待釋放鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "---" + "B");
flag = false;
LOCK.notify();//喚醒生產者線程,只有當前線程釋放鎖後才能被喚醒
}
}
}
};
t1.start();
t2.start();
}
}
簡單死鎖例子
package arithmetic;
/**
* Created by Hollake on 2019\7\17 0017 22:08.
*/
public class Main2 {
static boolean flag = false;
public static void main(String[] args) {
Object a = new Object();
Object b = new Object();
Thread t1 = new Thread(){
public void run(){
synchronized (a) {//加鎖
try {
Thread.sleep(20);//必須進行睡眠等待,不睡眠等待可以,但是一般不會發生死鎖,因爲程序執行太快
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {//拿到a鎖的情況下還想拿到b鎖,這與另外一個線程情況正好相反,
// 持有資源,不釋放資源,還需要其他線程持有的資源,死鎖的條件
System.out.println("不會執行到這裏");
}
}
}
};
Thread t2 = new Thread(){
public void run(){
synchronized (b) {//加鎖
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println("不會執行到這裏");
}
}
}
};
t1.start();
t2.start();
}
}
這個也是交替打印AB
package arithmetic;
import java.util.LinkedList;
/**
* Created by Hollake on 2019\6\24 0024 20:41.
*/
public class SwapPrint {
public static void main(String[] args) throws InterruptedException {
LinkedList<String> list = new LinkedList<>();
list.add("A");
list.add("B");
list.add("A");
list.add("B");
Object a = new Object();
Object b = new Object();
MyThread myThread1 = new MyThread(b,a,list);
MyThread myThread2 = new MyThread(a,b,list);
(new Thread(myThread1)).start();
Thread.sleep(100);
(new Thread(myThread2)).start();
}
}
class MyThread implements Runnable {
private LinkedList<String> list;
private Object pre;
private Object self;
public MyThread( Object pre, Object self,LinkedList<String> list) {
this.self = self;
this.pre = pre;
this.list = list;
}
@Override
public void run() {
while ( !list.isEmpty() ){
synchronized (pre) {//先拿到前一個線程的鎖
synchronized (self) {//接着拿到自己的鎖
System.out.println(Thread.currentThread() + list.poll());
self.notify();//喚醒另外一個線程
}
try {
pre.wait();//釋放前一個線程的鎖,中止當前線程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
交替打印字符串,例如:hello world
import java.util.LinkedList;
/**
* Created by Hollake on 2019\7\17 0017 22:08.
*/
public class Main2 {
static boolean flag = false;
static String str = "HELLO WORLD";
static int max = str.length();
public static void main(String[] args) {
Object LOCK = new Object();
LinkedList<String> list = new LinkedList<>();
for (int i = 0; i < max; i++) {
list.add(String.valueOf(str.charAt(i)));
}
Thread t1 = new Thread(){
public void run(){
while ( max > 0 ) {
synchronized (list) {//加鎖
while ( flag ) {
try {
list.wait();//滿足條件就釋放鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//在這裏爲什兒要進行list是否爲null的判斷呢,仔細思考一下,如果不判斷,例如打印兩個字母ab,
// 第一次線程t1打印a後,繼續到try中,調用list.wait()方法,釋放鎖,線程t2拿到鎖,繼續打印b,
// 接着同樣的釋放鎖,線程t1從try中的wait()方法中被喚醒,繼續執行,但是list中已經沒有了元素,
// 所以調用pop()方法直接會拋出空指針異常
if (list.size() > 0) {
System.out.println(Thread.currentThread().getName() + "---" + list.pop());
}
max--;
flag = true;
list.notify();//喚醒t2線程,只有當前線程釋放鎖後才能被喚醒
}
}
}
};
Thread t2 = new Thread(){
public void run(){
while ( max > 0 ) {
synchronized (list) {//加鎖
while ( !flag ) {
try {
list.wait();//釋放鎖等待被喚醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (list.size() > 0) {
System.out.println(Thread.currentThread().getName() + "---" + list.pop());
}
max--;
flag = false;
list.notify();//喚醒t1線程,只有當前線程釋放鎖後才能被喚醒
}
}
}
};
t1.start();
t2.start();
}
}