温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java中如何实现线程通信

发布时间:2021-06-21 18:17:27 来源:亿速云 阅读:101 作者:Leah 栏目:大数据

今天就跟大家聊聊有关Java中如何实现线程通信,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

1、synchronized加wait/notify方式

/**
 * 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();
    }
}

2、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();
        }
    }
}

3、闭锁方式

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();
        }
    }
}

4、栅栏的方式

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();
        }
    }
}

5、信号量的方式

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的使用

/**
 * 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的使用

/**
 * 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();
    }
}

看完上述内容,你们对Java中如何实现线程通信有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI