多线程之间通信
概述
马老师多线程视频学习总结(好记性不如烂笔头)。
多线程之间通信
使用volatile实现通信
模拟情形: 设计一个容器,两个线程。线程一给容器里面add元素,当容器中的元素个数为5个时,线程二结束。
未使用volatile关键字:
package com.wz.code.test.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class Container1 {
List lists = new ArrayList<>();
public boolean add(Object o) {
return lists.add(o);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
Container1 c1 = new Container1();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
c1.add(new Object());
System.out.println("add " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "t1").start();
new Thread(() -> {
while (true) {
if (c1.size() == 5)
break;
}
System.out.println("t2 done, size is " + c1.size());
}, "t2").start();
}
}
程序执行结果:
使用volatile关键字:
package com.wz.code.test.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class Container2 {
volatile List lists = new ArrayList<>();
public boolean add(Object o) {
return lists.add(o);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
Container2 c1 = new Container2();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
c1.add(new Object());
System.out.println("add " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "t1").start();
new Thread(() -> {
while (true) {
if (c1.size() == 5) {
break;
}
}
System.out.println("t2 done, size is " + c1.size());
}, "t2").start();
}
}
使用synchronized 关键字:
package com.wz.code.test.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class Container3 {
volatile List lists = new ArrayList<>();
public synchronized boolean add(Object o) {
return lists.add(o);
}
public synchronized int size() {
return lists.size();
}
public static void main(String[] args) {
Container3 c1 = new Container3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
c1.add(new Object());
System.out.println("add " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "t1").start();
new Thread(() -> {
while (true) {
if (c1.size() == 5) {
break;
}
}
System.out.println("t2 done, size is " + c1.size());
}, "t2").start();
}
}
使用synchronized,wait,notify/notifyAll
- wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用,即,一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法。
- 由于 wait()、notify/notifyAll() 在synchronized 代码块执行,说明当前线程一定是获取了锁的。
- 当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。
只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。 - notify唤醒沉睡的线程后,线程会接着上次的执行继续往下执行。所以在进行条件判断时候,可以先把 wait 语句忽略不计来进行考虑,显然,要确保程序一定要执行,并且要保证程序直到满足一定的条件再执行,要使用while来执行,以确保条件满足和一定执行。
package com.wz.code.test.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class Container4 {
volatile List lists = new ArrayList<>();
public boolean add(Object o) {
return lists.add(o);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
Container4 c1 = new Container4();
// 不要使用字符串座位锁定对象
final Object lock = new Object();
new Thread(() -> {
System.out.println("t2启动");
synchronized (lock) {
if (c1.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.notify();
System.out.println("t2结束");
}
}, "t2").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
new Thread(() -> {
System.out.println("t1启动");
synchronized (lock) {
for (int i = 0; i < 10; i++) {
c1.add(new Object());
System.out.println("t1 add " + i);
if (c1.size() == 5) {
lock.notify();
// wait释放锁, notify不释放锁
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("t1结束");
}
}, "t1").start();
}
}
CountDownLatch实现线程间通信
package com.wz.code.test.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Container5 {
volatile List lists = new ArrayList<>();
public boolean add(Object o) {
return lists.add(o);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
Container5 c1 = new Container5();
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
System.out.println("t2启动");
if (c1.size() != 5) {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2结束");
}, "t2").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
new Thread(() -> {
System.out.println("t1启动");
for (int i = 0; i < 10; i++) {
c1.add(new Object());
System.out.println("t1 add " + i);
if (c1.size() == 5) {
latch.countDown();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("t1结束");
}, "t1").start();
}
}
使用ReentrantLock的Condition实现线程间通信
package com.wz.code.test.thread;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyContainer2<T> {
private final LinkedList<T> list = new LinkedList<>();
private final int MAX = 10;
private static int count = 0;
private Lock lock = new ReentrantLock();
private Condition producer = lock.newCondition();
private Condition customer = lock.newCondition();
public void put(T t) {
lock.lock();
try {
while (list.size() == MAX) {
producer.await();
}
list.add(t);
++count;
customer.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public T get() {
T t = null;
lock.lock();
try {
while (list.size() == 0) {
customer.await();
}
t = list.removeFirst();
count--;
producer.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return t;
}
public static void main(String[] args) {
MyContainer2<String> c = new MyContainer2<String>();
CountDownLatch latch = new CountDownLatch(12);
// 10个消费者
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 5; j++)
System.out.println(Thread.currentThread().getName() + " " + c.get());
latch.countDown();
}, "c" + i).start();
}
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < 2; i++) {
new Thread(() -> {
for (int j = 0; j < 25; j++)
c.put((Thread.currentThread().getName()) + " " + j);
latch.countDown();
}, "p" + i).start();
}
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("程序结束: count " + count);
}
}