Java多线程(2)
线程间的通信
线程间的通信又称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号或等待信号
等待通知机制
厨师与服务员的交互在桌子上:
-
厨师做完一道菜的时间不确定,所以厨师将菜放到桌子上的时间也不确定
-
服务员取到菜的时间取决于厨师,所以服务员有“等待”的状态
-
服务员怎么能拿到菜?取决于厨师,厨师将菜放到桌子上,就相当于通知服务员拿菜了
这个过程就体现了等待通知机制
wait() notif()
wait():
调用后,这会强制当前线程等待,直到某个其他线程在同一个对象上调用notify()或notifyAll()
为此,当前线程必须拥有对象的监视器。这可能发生在:
-
我们已经为给定对象执行了同步实例方法
-
我们在给定对象上执行了synchronized块的主体
-
通过为Class类型的对象执行同步静态方法
notify():
对于在此对象的监视器上等待的所有线程(通过使用任何一个wait()方法),方法notify()通知任何一个线程任意唤醒。确切唤醒哪个线程的选择是非确定性的 ,取决于实现。
notifyAll():
方法只是唤醒正在此对象的监视器上等待的所有线程
说明:
执行完notify()后,当前线程不会马上释放对象锁,呈wait状态的线程也不能马上获得对象锁,要等到执行notify()方法的线性将程序执行完毕后,当前线程才释放锁
如果第一个获得对象锁的wait线程执行完后,没有再次使用notify,则即便对象锁已经空闲,其他wait状态的线程由于没有通知也继续处于wait状态
例子:
模拟图片下载后查看的过程,图片是要下载完成之后才能执行查看这个操作
public class T1 {
public static void main(String[] args) {
//写两个线程 1.图片下载
Object obj=new Object();
Thread download=new Thread(){
public void run() {
System.out.println("开始下载图片");
for (int i = 0; i < 101; i+=10) {
System.out.println("down"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("图片下载成功");
synchronized (obj) {
obj.notify();//唤起
}
System.out.println("开始下载附件");
for (int i = 0; i < 101; i+=10) {
System.out.println("附件下载"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("附件下载成功");
}
};
//2.图片展示
Thread show=new Thread(){
public void run(){
synchronized (obj) {
try {
obj.wait();//阻塞当前
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("show:开始展示图片");
System.out.println("图片展示完毕");
}
}
};
download.start();
show.start();
}
}
来看生产者/消费者的例子:
一个生产者和一个消费者共同操作一个栈,栈最大容量为1
public class MyStack {
private List list = new ArrayList();
synchronized public void push(){
try {
if (list.size() == 1){
this.wait();
}
list.add("any = " + Math.random());
this.notify();
System.out.println("push " + list.size());
} catch (InterruptedException e){
e.printStackTrace();
}
}
synchronized public String pop(){
String val = "";
try {
if (list.size() == 0){
System.out.println("pop "+Thread.currentThread().getName());
this.wait();
}
val = "" + list.get(0);
list.remove(0);
this.notify();
System.out.println("pop " + list.size());
} catch (InterruptedException e){
e.printStackTrace();
}
return val;
}
}
public class C {
private MyStack myStack;
public C(MyStack myStack) {
this.myStack = myStack;
}
public void popService(){
System.out.println("pop " + myStack.pop());
}
}
public class P {
private MyStack myStack;
public P(MyStack myStack) {
this.myStack = myStack;
}
public void pushService(){
myStack.push();
}
}
public class C_thread extends Thread{
private C c;
public C_thread(C c) {
this.c = c;
}
@Override
public void run() {
while (true){
c.popService();
}
}
}
public class P_thread extends Thread{
private P p;
public P_thread(P p) {
this.p = p;
}
@Override
public void run() {
while (true){
p.pushService();
}
}
}
public class Run {
// 生产者 消费者 容器size不会大于1
public static void main(String[] args) {
MyStack myStack = new MyStack();
P p = new P(myStack);
C c = new C(myStack);
P_thread p_thread = new P_thread(p);
C_thread c_thread = new C_thread(c);
p_thread.start();
c_thread.start();
}
}
多个生产者多个消费者:
public class MyStack {
private List list = new ArrayList();
synchronized public void push(){
try {
// 当一个生产者 多个消费者操作栈 会出现假死现象
// 应该push中使用了if判断
// 将 if 改成 while
// 以及notify 改成 notifyAll
while (list.size() == 1){
this.wait();
}
list.add("any = " + Math.random());
this.notifyAll();
System.out.println("push " + list.size());
} catch (InterruptedException e){
e.printStackTrace();
}
}
synchronized public String pop(){
String val = "";
try {
while (list.size() == 0){
System.out.println("pop "+Thread.currentThread().getName());
this.wait();
}
val = "" + list.get(0);
list.remove(0);
this.notifyAll();
System.out.println("pop " + list.size());
} catch (InterruptedException e){
e.printStackTrace();
}
return val;
}
}
public class P {
private MyStack myStack;
public P(MyStack myStack) {
this.myStack = myStack;
}
public void pushService(){
myStack.push();
}
}
public class C {
private MyStack myStack;
public C(MyStack myStack) {
this.myStack = myStack;
}
public void popService(){
System.out.println("pop " + myStack.pop());
}
}
public class C_thread extends Thread{
private C c;
public C_thread(C c) {
this.c = c;
}
@Override
public void run() {
while (true){
c.popService();
}
}
}
public class P_thread extends Thread{
private P p;
public P_thread(P p) {
this.p = p;
}
@Override
public void run() {
while (true){
p.pushService();
}
}
}
public class Run {
public static void main(String[] args) {
// 多消费者 多生产者
MyStack myStack = new MyStack();
P p1 = new P(myStack);
P p2 = new P(myStack);
P p3 = new P(myStack);
P p4 = new P(myStack);
P p5 = new P(myStack);
P_thread p_thread_1 = new P_thread(p1);
P_thread p_thread_2 = new P_thread(p2);
P_thread p_thread_3 = new P_thread(p3);
P_thread p_thread_4 = new P_thread(p4);
P_thread p_thread_5 = new P_thread(p5);
p_thread_1.start();
p_thread_2.start();
p_thread_3.start();
p_thread_4.start();
p_thread_5.start();
C c1 = new C(myStack);
C c2 = new C(myStack);
C c3 = new C(myStack);
C c4 = new C(myStack);
C c5 = new C(myStack);
C_thread c_thread1 = new C_thread(c1);
C_thread c_thread2= new C_thread(c2);
C_thread c_thread3 = new C_thread(c3);
C_thread c_thread4 = new C_thread(c4);
C_thread c_thread5 = new C_thread(c5);
c_thread1.start();
c_thread2.start();
c_thread3.start();
c_thread4.start();
c_thread5.start();
}
}
例子:
创建20个线程,10个线程将数据备份到数据库A,10个线程将数据备份到数据库B,备份的过程是交叉进行的
public class DBTools {
volatile private boolean prevIsA = false;
synchronized public void backupA(){
try {
while (prevIsA == true){
wait();
}
for (int i = 0; i < 5; i++) {
System.out.println(" * * * * * ");
}
} catch (InterruptedException e){
e.printStackTrace();
}
prevIsA = true;
notifyAll();
}
synchronized public void backupB(){
try {
while (prevIsA == false){
wait();
}
for (int i = 0; i < 5; i++) {
System.out.println(" + + + + +");
}
prevIsA= false;
notifyAll();
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
public class BackupA extends Thread{
private DBTools dbTools;
public BackupA(DBTools dbTools) {
this.dbTools = dbTools;
}
@Override
public void run() {
dbTools.backupA();
}
}
public class BackupB extends Thread{
private DBTools dbTools;
public BackupB(DBTools dbTools) {
this.dbTools = dbTools;
}
@Override
public void run() {
dbTools.backupB();
}
}
public class Run {
public static void main(String[] args) {
DBTools dbTools = new DBTools();
for (int i = 0; i < 20; i++) {
BackupB b = new BackupB(dbTools);
b.start();
BackupA a = new BackupA(dbTools);
a.start();
}
}
}