多线程之间通信

概述

马老师多线程视频学习总结(好记性不如烂笔头)。

多线程之间通信

使用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);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值