Java实现线程通讯的几种方式

本文共总结了5种方式,经过代码举例的方式进行展现。5种方式为:synchronized加wait/notify方式、ReentrantLock加Condition方式、闭锁的方式、栅栏的方式、信号量的方式。java

最后还介绍了join和yield的使用。ide

一、synchronized加wait/notify方式ui

/**
 * wait和notify的使用
 * wait和notify必须应用在synchronized块或方法内
 * 下面的代码向跳交谊舞同样互相控制着对方的输出
 */
public class MutiThread_WaitNotify {
    public static void main(String[] args) {
        final Object lock = new Object();
        Thread a = new Thread(new Runnable(){
            @Override
            public void run(){
                synchronized (lock){
                    try{
                        lock.wait();
                        System.out.println("A-1");
                        lock.notify();
                        lock.wait();
                        System.out.println("A-2");
                        lock.notify();
                        lock.wait();
                        System.out.println("A-3");
                        lock.notify();
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread b = new Thread(new Runnable(){
            @Override
            public void run(){
                synchronized (lock){
                    try{
                        System.out.println("B-1");
                        lock.notify();
                        lock.wait();
                        System.out.println("B-2");
                        lock.notify();
                        lock.wait();
                        System.out.println("B-3");
                        lock.notify();
                        lock.wait();
                        System.out.println("B-4");
                    }catch(InterruptedException e){
                        e.printStackTrace();;
                    }
                }
            }
        });
        a.start();
        b.start();
    }
}

二、ReentrantLock加Condition方式线程

/**
 * ReentrantLock和Condition的使用
 * 在使用Conditioin的await和signal时,必须将这两个方法写在ReentrantLock的lock方法以后
 */
public class MutiThread_ReentrantLock_Condition {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        int i=1;
        for(; i<=6; i++){
            final int k = i;
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        lock.lock();
                        System.out.println("ThreadNo:A" + k + " is locked");
                        // 经过condition.await将线程阻塞
                        condition.await();
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }finally{
                        lock.unlock();
                        System.out.println("ThreadNo:A"+k + " is unlocked");
                    }
                }
            });

            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    if(k == 6){
                        try{
                            lock.lock();
                            System.out.println("All Threads is signaled");
                            // 经过condition.signalAll唤醒全部线程
                            condition.signalAll();
                        }catch(Exception e){
                            e.printStackTrace();
                        }finally{
                            lock.unlock();
                        }
                    }else{
                        System.out.println("threads can't signaled, wait a moment.");
                    }
                }
            });
            t1.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
        }
    }
}

三、闭锁方式事件

import java.util.concurrent.CountDownLatch;
/**
 * 闭锁的使用
 * 闭锁用于等待事件,当闭锁到达结束状态(本例中是闭锁的计数器值减为0)以前,全部线程都等待,当闭锁到达结束状态时,全部线程都经过
 * 闭锁是一次性的,当闭锁到达结束状态后,将不会被重置,这个锁会永远打开并容许全部线程经过。
 * 能够将代码中的NUM变量值变为2和4,分别试试什么效果
 */
public class MutiThread_CountDownLatch {
    public static void main(String[] args) {
        // 定义闭锁,并设置闭锁的计数器值为3
        CountDownLatch lock = new CountDownLatch(3);
        // 循环定义3个线程
        int NUM = 3;
        for(int i=1; i<=NUM; i++){
            final int k = i;
            Thread a = new Thread(new Runnable(){
                @Override
                public void run(){
                    try{
                        Thread.sleep(k * 1000);
                        System.out.println("ThreadNo:A"+k);
                        // 每一个线程在休眠指定时间后将闭锁的计数器值减1,当闭锁的计数器值减到0时,闭所将被打开,从而使第二个循环中的全部线程才能经过
                        lock.countDown();
                        // 打印闭锁计数器的值
                        System.out.println("ThreadNo:A"+k+"; getCount:"+lock.getCount());
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            });
            a.start();
        }
        // 循环定义2个线程
        for(int i=1; i<=2; i++){
            final int k = i;
            Thread b = new Thread(new Runnable(){
                @Override
                public void run(){
                    try{
                        System.out.println("ThreadNo:B"+k+" is waiting...");
                        // 当闭锁的计数器值不为0时,线程将在此处被中断
                        lock.await();
                        // 当闭锁的计数器值等于0时,闭锁将被打开,全部等待的线程都将被唤醒
                        System.out.println("ThreadNo:B"+k+" is notify");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            });
            b.start();
        }
    }
}

四、栅栏的方式资源

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 栅栏的使用
 * 栅栏用于等待线程,全部线程必须同时到达栅栏,才能继续执行
 * 栅栏不是一次性的,能够被重置。
 * 能够将代码中的NUM变量值变为5和7,分别试试什么效果
 */
public class MutiThread_CyclicBarrier {
    public static void main(String[] args) {
        // 定义栅栏,并设置栅栏须要等待的线程数为6
        CyclicBarrier barrier = new CyclicBarrier(6);
        int NUM = 100;
        for(int i=1; i<=NUM; i++){
            final int k = i;
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        Thread.sleep(k * 1000);
                        System.out.println("ThreadNo:"+k+" is waiting, getNumberWaiting:" + barrier.getNumberWaiting());
                        // 栅栏设置的等待线程数为6,当线程数不够6个时,全部线程将在此等待
                        barrier.await();
                        // 当线程数达到6个时,栅栏将被打开,全部线程都将被唤醒
                        System.out.println("ThreadNo:"+k+" is notify");
                        // 栅栏被重置,以便下次继续使用
                        barrier.reset();
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }
}

五、信号量的方式get

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

/**
 * 信号量的使用
 * 信号量用于控制同时访问某个资源的线程数量,信号量还能够用于实现某个资源池。
 * 信号量管理者一组虚拟的许可,线程在执行操做时首先要得到许可,若是信号量的许可数量为0,那么accquire将阻塞直到有许可为止
 * 信号量不是一次性的,当信号链的许可用完以后,能够经过release释放许可
 */
public class MutiThread_Semaphore {
    public static void main(String[] args) {
        // 定义信号量,并设置信号量的容许发放的最大许可数量为6
        final Semaphore semaphore = new Semaphore(6);
        // 定义集合,当信号量未发放的许可数量大于0则容许线程向集合内添加元素
        final List<String> set = new ArrayList<>();
        int i = 1;
        while(true){
            final int k = i++;
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    boolean res = false;
                    try{
                        System.out.println("ThreadNo:A"+k+", availablePermits:"+semaphore.availablePermits());
                        // 当信号量容许发放的许可数量大于0,则会向集合内添加元素,不然将被中断于此
                        semaphore.acquire();
                        res = set.add("1");
                        System.out.println("ThreadNo:A"+k+" add item success");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }finally{
                        if(!res){
                            semaphore.release();
                        }
                    }
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    if(semaphore.availablePermits() == 0){
                        // 若是信号量容许发放的许可数量等于0,则释放制定数量的许可
                        semaphore.release(3); //释放3个许可
                        System.out.println("ThreadNo:B"+k+" releasePermitNum:"+semaphore.availablePermits());
                    }
                }
            });
            t.start();
            t2.start();
            System.out.println("the num of set:"+set.size());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

A、join的使用it

/**
 * join的使用
 * 实现当调用join的线程执行完毕后,其余线程才能执行
 */
public class MutiThread_Join {
    public static void main(String[] args) {
        Thread a = new Thread(new Runnable(){
            @Override
            public void run(){
                printNumber("A");
            }
        });
        Thread b = new Thread(new Runnable(){
            @Override
            public void run(){
                printNumber("B");
            }
        });
        try{
            a.start();
            // a线程执行完毕后,b线程才能执行
            a.join();
            b.start();
        }catch(InterruptedException e){
            e.printStackTrace();;
        }
    }
    public static void printNumber(String s){
        System.out.println(s+" print:"+s);
    }
}

B、yield的使用io

/**
 * yield,当一个线程中调用了这个方法后,这个线程就会把本身的CPU执行时间让给本身或其它线程,
 * 注意是让给本身或其它线程,并非单纯让给其余线程。yield执行后,能让当前线程由运行状态
 * 进入到就绪状态,将本身的CPU时间片让出来,让出来以后有多是其它线程执行,也有多是该线程
 * 继续执行。优先级高的线程并不必定是首先执行,而是首先执行的几率会高一些。优先级在大量线程
 * 执行的时候才能体现的出来。
 */
public class MutiThread_yield {
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++){
                    System.out.println("ThreadNo:A"+i);
                    Thread.yield();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++){
                    System.out.println("ThreadNo:B"+i);
                    Thread.yield();
                }
            }
        });
        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();
    }
}
相关文章
相关标签/搜索