Java多线程与并发库高级应用-工具类介绍
发布日期:2021-07-12 08:49:38 浏览次数:6 分类:技术文章

本文共 27770 字,大约阅读时间需要 92 分钟。

java.util.concurrent.Lock

1、Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,

锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。

  lock替代synchronized

  

class Outputer {        Lock lock = new ReentrantLock();        public void output(String name) {            int len = name.length();            lock.lock();                try{                for (int i = 0; i < len; i++) {                    char c = name.charAt(i);                    System.out.print(c);                }            }finally{                lock.unlock();  //这里防止内部代码出现异常,即无论如何最后都会释放锁            }            lock.unlock();            System.out.println();        }}

 

售票系统

package com.java.juc;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class TestLock {    public static void main(String[] args) {        Ticket ticket = new Ticket();        new Thread(ticket, "窗口1售票").start();        new Thread(ticket, "窗口2售票").start();        new Thread(ticket, "窗口3售票").start();    }}class Ticket implements Runnable {    private int ticket = 100;    private Lock lock = new ReentrantLock();    @Override    public void run() {        while (true) {            lock.lock();            try {                if (ticket > 0) {                    Thread.sleep(20);                    System.out.println(Thread.currentThread().getName()                            + ",余票量:" + ticket--);                }            } catch (InterruptedException e) {                e.printStackTrace();            } finally {                lock.unlock();            }        }    }}

 

 

 

2、读写锁:

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。

* 如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;
* 如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。
* 总之,读的时候上读锁,写的时候上写锁!

/* 面试题:3个线程读,3个线程写 同一个数据 */public class ReadWriteLockTest {    public static void main(String[] args) {        final Queue3 queue = new Queue3();        for(int i = 0;i<3;i++){            new Thread(new Runnable() {                @Override                public void run() {                    while(true){                        queue.get();                    }                }            }).start();            new Thread(new Runnable() {                @Override                public void run() {                    queue.set(new Random().nextInt(10000));                }            }).start();        }    }}class Queue3{    private Object data = null; //共享数据 ,只能有一个线程写该数据,但可以有多个线程同时读    ReadWriteLock rwl = new ReentrantReadWriteLock();  //读写锁        public void get(){        try {            rwl.readLock().lock();  //上读锁 可以有多个线程同时读            System.out.println(Thread.currentThread().getName() + " be ready to read data!");            Thread.sleep((long)Math.random() * 1000);            System.out.println(Thread.currentThread().getName() + " have read data : "+ data);        } catch (InterruptedException e) {        }finally{            rwl.readLock().unlock();  //释放读锁        }    }    public void set(Object data){        try {            rwl.writeLock().lock();  //添加写锁,保证只能有一个线程进行写操作            System.out.println(Thread.currentThread().getName() + " be read to write data: "+ data);            Thread.sleep((long)Math.random() * 1000);            this.data = data;            System.out.println(Thread.currentThread().getName() + "has write data");        } catch (InterruptedException e) {            e.printStackTrace();        }finally{            rwl.writeLock().unlock();  //释放写锁        }    }}

 简单的读写锁示例

package com.java.juc;import java.util.Random;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;public class TestReadWriteLock {    public static void main(String[] args) {        final ReadWriteLockDemo demo = new ReadWriteLockDemo();        new Thread(new Runnable(){            @Override            public void run() {                demo.set(new Random().nextInt(5000));            }        },"Write").start();                for(int i = 0;i<100;i++){            new Thread(new Runnable() {                @Override                public void run() {                    demo.get();                }            }, "Read").start();        }    }}class ReadWriteLockDemo{    private int number = 0;        private ReadWriteLock lock = new ReentrantReadWriteLock();        public void get(){        try{            lock.readLock().lock();            System.out.println(Thread.currentThread().getName() +" "+number);        }finally{            lock.readLock().unlock();        }    }    public void set(int number){        try{            lock.writeLock().lock();            this.number = number;        }finally{            lock.writeLock().unlock();        }    }}

 

 

 Hibernate的一个面试题:

  User user = session.load(id,User.class);

  User user = session.get(id,User.class);

  以上两个的却别。

  get()方式,直接查询数据库,如果查询到赋值给User对象,如果没有查询到则返回为null

  load()方式,实际上是从User的一个代理中获取, User$Proxy中包含有一个真实的User对象,当调用load()时,如果成员变量User为null,则从数据库查询将记录返回并给User赋值,当load()时User不为null,则直接返回User对象

 

/** * 面试题: 设计一个缓存系统 * @author Administrator * */public class CacheDemo {    Map
cache = new HashMap
(); public static void main(String[] args) { } private ReadWriteLock rwl = new ReentrantReadWriteLock(); public Object getData(String key){ rwl.readLock().lock(); Object value = null; try { value = cache.get(key); if(value == null){ rwl.readLock().unlock(); rwl.writeLock().lock(); try { if(value == null){ //防止后边线程加载数据,使用双端检测机制 value = "xxx"; //queryDB cache.put(key, value); } }finally{ rwl.writeLock().unlock(); } rwl.readLock().lock(); } } catch (Exception e) { }finally{ rwl.readLock().unlock(); } return value; } }

 

 

ReadWriteLock javaAPI中有缓存的代码:

class CachedData {   Object data;   volatile boolean cacheValid;   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();   void processCachedData() {     rwl.readLock().lock();     if (!cacheValid) {        // Must release read lock before acquiring write lock        rwl.readLock().unlock();        rwl.writeLock().lock();        // Recheck state because another thread might have acquired        //   write lock and changed state before we did.        if (!cacheValid) {          data = ...          cacheValid = true;        }        // Downgrade by acquiring read lock before releasing write lock        rwl.readLock().lock();        rwl.writeLock().unlock(); // Unlock write, still hold read     }     use(data);     rwl.readLock().unlock();   } }

 

3、Condition 实现线程通信

传统的线程通信方式

/* * 传统线程通信 * 主线程和子线程分别打印 100次 和 10次,循环50次 */public class TraditionalThreadCommunication2 {    public static void main(String[] args) {        final Buiness buiness = new Buiness();        new Thread(new Runnable() {            @Override            public void run() {                for(int i = 1;i<=50;i++){                    buiness.sub(i);                }            }        }).start();                for(int i = 1;i<=50;i++){            buiness.main(i);        }    }        static class Buiness{        private boolean isShouldSub = false;  //主线程先打印        public synchronized void main(int j){ //进行同步,防止在打印时被其他线程干扰            while(isShouldSub){  //这里使用while 防止假唤醒                try {                    this.wait();  //wait() 和 notify() 必须出现在synchronized同步中                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            for(int i = 1;i<=100;i++){                System.out.println("main thread print "+ i + " loop of " + j);            }            isShouldSub = true;            this.notify();        }        public synchronized void sub(int j){            while(!isShouldSub){                try {                    this.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            for(int i = 1 ; i<=10;i++){                System.out.println("sub thread print "+ i + " loop of " + j);            }            isShouldSub = false;            this.notify();        }    }}

 

 

将上述程序改写为使用Condition

/* * 传统线程通信 * 主线程和子线程分别打印 100次 和 10次,循环50次 * 改写成使用 Condition 的方式 */public class TraditionalThreadCommunication2 {    public static void main(String[] args) {        final Buiness buiness = new Buiness();        new Thread(new Runnable() {            @Override            public void run() {                for(int i = 1;i<=50;i++){                    buiness.sub(i);                }            }        }).start();                for(int i = 1;i<=50;i++){            buiness.main(i);        }    }        /**     * 将程序改写为使用Lock&Condition的方式进行 同步和通信     * @author Administrator     *     */    static class Buiness{        Lock lock = new ReentrantLock();        Condition condition = lock.newCondition();        private boolean isShouldSub = false;  //主线程先打印        public void main(int j){ //进行同步,防止在打印时被其他线程干扰            lock.lock();            try {                while(isShouldSub){  //这里使用while 防止假唤醒                    try {                        condition.await();//                    this.wait();  //wait() 和 notify() 必须出现在同步监视器内部中                    } catch (Exception e) {                        e.printStackTrace();                    }                }                for(int i = 1;i<=100;i++){                    System.out.println("main thread print "+ i + " loop of " + j);                }                isShouldSub = true;                condition.signal();//            this.notify();             } finally {                lock.unlock();            }        }        public void sub(int j){            lock.lock();            try {                while(!isShouldSub){                    try {                        condition.await();//                    this.wait();                    } catch (Exception e) {                        e.printStackTrace();                    }                }                for(int i = 1 ; i<=10;i++){                    System.out.println("sub thread print "+ i + " loop of " + j);                }                isShouldSub = false;                condition.signal();//            this.notify();            } finally{                lock.unlock();            }        }    }}

main thread print 1 loop of 1

main thread print 2 loop of 1
main thread print 3 loop of 1
main thread print 4 loop of 1
main thread print 5 loop of 1
main thread print 6 loop of 1
main thread print 7 loop of 1
...
main thread print 99 loop of 1
main thread print 100 loop of 1
sub thread print 1 loop of 1
sub thread print 2 loop of 1
sub thread print 3 loop of 1
sub thread print 4 loop of 1
sub thread print 5 loop of 1
sub thread print 6 loop of 1
sub thread print 7 loop of 1
sub thread print 8 loop of 1
sub thread print 9 loop of 1
sub thread print 10 loop of 1
main thread print 1 loop of 2
main thread print 2 loop of 2
main thread print 3 loop of 2
main thread print 4 loop of 2
main thread print 5 loop of 2
main thread print 6 loop of 2
main thread print 7 loop of 2
main thread print 8 loop of 2
main thread print 9 loop of 2
...
main thread print 99 loop of 2
main thread print 100 loop of 2
sub thread print 1 loop of 2
sub thread print 2 loop of 2
sub thread print 3 loop of 2
sub thread print 4 loop of 2
sub thread print 5 loop of 2
sub thread print 6 loop of 2
sub thread print 7 loop of 2
sub thread print 8 loop of 2
sub thread print 9 loop of 2
sub thread print 10 loop of 2
main thread print 1 loop of 3
main thread print 2 loop of 3
main thread print 3 loop of 3

...

 

使用Condition比传统的好处

可以实现多路Condition ,在javaAPI中有

class BoundedBuffer {   final Lock lock = new ReentrantLock();   final Condition notFull  = lock.newCondition();    final Condition notEmpty = lock.newCondition();    final Object[] items = new Object[100];   int putptr, takeptr, count;   public void put(Object x) throws InterruptedException {     lock.lock();     try {       while (count == items.length)         notFull.await();       items[putptr] = x;       if (++putptr == items.length) putptr = 0;       ++count;       notEmpty.signal();     } finally {       lock.unlock();     }   }   public Object take() throws InterruptedException {     lock.lock();     try {       while (count == 0)         notEmpty.await();       Object x = items[takeptr];       if (++takeptr == items.length) takeptr = 0;       --count;       notFull.signal();       return x;     } finally {       lock.unlock();     }   } }

使用多路Condition,可以扩展上述的一个例子,老大打印完 -> 老二   老二-> 老三  老三-> 老大  老大-> 老二...

 

/** * 第一个线程循环100次,第二个线程循环10次,第三个线程循环20次,如此循环50次,请写出程序 这里使用Condition *  * @author Administrator *  */public class ThreeConditionCommunication {    public static void main(String[] args) {        final Business2 business = new Business2();        new Thread(new Runnable() {            @Override            public void run() {                for (int i = 1; i <= 50; i++) {                    business.sub2(i);                }            }        }).start();        new Thread(new Runnable() {            @Override            public void run() {                for (int i = 1; i <= 50; i++) {                    business.sub3(i);                }            }        }).start();        for (int i = 1; i <= 50; i++) {            business.main(i);        }    }}class Business2 {    Lock lock = new ReentrantLock();    Condition condition1 = lock.newCondition();    Condition condition2 = lock.newCondition();    Condition condition3 = lock.newCondition();    private int shoudeSub = 1;    public void sub2(int i) {        lock.lock();        try {            while (shoudeSub != 2) { // 这里也可以用 if ,用while比较好一些 As in the one argument                                    // version, interrupts and spurious wakeups are                                    // possible, and this method should always be                                    // used in a loop                try { // 防止线程有可能被假唤醒 (while放在这里提现了水准)                    condition2.await();  //等待                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            for (int j = 1; j <= 100; j++) {                System.out.println("sub2 thread sequence of " + j + ", loop of " + i);            }            shoudeSub = 3;            condition3.signal();//唤醒        } finally{            lock.unlock();        }    }    public void sub3(int i) {        lock.lock();        try {            while (shoudeSub != 3) { // 这里也可以用 if ,用while比较好一些 As in the one argument                // version, interrupts and spurious wakeups are                // possible, and this method should always be                // used in a loop                try { // 防止线程有可能被假唤醒 (while放在这里提现了水准)                    condition3.await();  //等待                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            for (int j = 1; j <= 20; j++) {                System.out.println("sub3 thread sequence of " + j + ", loop of " + i);            }            shoudeSub = 1;            condition1.signal();//唤醒        } finally{            lock.unlock();        }    }    public void main(int i) {        lock.lock();        try {            while (shoudeSub != 1) {                try {                    condition1.await();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            for (int j = 1; j <= 10; j++) {                System.out.println("main thread sequence of " + j + ", loop of "                        + i);            }            shoudeSub = 2;            condition2.signal();        } finally{            lock.unlock();        }    }    /**     *      * synchronized (obj) { 这里的obj与obj.wait必须相同,否则会抛异常 while (
) obj.wait(); ... // Perform action appropriate to condition } */}

 

Condition的一个例子:

 编写一个程序,开启3个线程 ,这三个线程的ID分别为 A,B, C,每个线程将自己的ID 在屏幕上打印10遍,要求输出的结果必须按顺序显示。

如:ABCABCABC.....依次递归

这里实现了一个比题目稍微难得例子,A 打印10次,B打印20次 ,C打印5次依次递归20次。

package com.java.juc;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class TestAlternative {    public static void main(String[] args) {        final Alternative alternative = new Alternative();        new Thread(new Runnable(){            @Override            public void run() {                for(int i = 1;i<=20;i++){                    alternative.loopA(i);                }            }        },"A").start();        new Thread(new Runnable(){            @Override            public void run() {                for(int i = 1;i<=20;i++){                    alternative.loopB(i);                }            }        },"B").start();        new Thread(new Runnable(){            @Override            public void run() {                for(int i = 1;i<=20;i++){                    alternative.loopC(i);                    System.out.println("-----------------");                }            }        },"C").start();            }}class Alternative{        private int number = 1;    private Lock lock = new ReentrantLock();    private Condition condition1 = lock.newCondition();    private Condition condition2 = lock.newCondition();    private Condition condition3 = lock.newCondition();        void loopA(int outerLoop){        lock.lock();        try{            while(number != 1){                condition1.await();            }            for(int i = 1;i<=10;i++){                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + outerLoop);            }            number = 2;            condition2.signal();        }catch(Exception e){        }finally {            lock.unlock();        }    }        void loopB(int outerLoop){        lock.lock();        try{            while(number != 2){                condition2.await();            }            for(int i = 1;i<=20;i++){                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + outerLoop);            }            number = 3;            condition3.signal();        }catch(Exception e){                    }finally{            lock.unlock();        }    }    void loopC(int outerLoop){        lock.lock();        try{            while(number != 3){                condition3.await();            }            for(int i = 1;i<=5;i++){                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + outerLoop);            }            number = 1;            condition1.signal();        }catch(Exception e){                    }finally{            lock.unlock();        }    }}

 

 

java5的Semaphere同步工具

  Semaphore实现信号灯

  Semaphore可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

  假设一个文件同时可以被3个人访问,来了5个人,同时只有3个访问。3个中任何一个出来后,等待的就可以进去了。

public class SemaphoreTest {    public static void main(String[] args) {        ExecutorService service = Executors.newCachedThreadPool();        final  Semaphore sp = new Semaphore(3);  //还有一个构造方法,Semaphore(int permits, boolean fair)  fair参数为true表示谁先来谁先进,一种公平的原则         for(int i=0;i<10;i++){            Runnable runnable = new Runnable(){                    public void run(){                    try {                        sp.acquire();                    } catch (InterruptedException e1) {                        e1.printStackTrace();                    }                    System.out.println("线程" + Thread.currentThread().getName() +                             "进入,当前已有" + (3-sp.availablePermits()) + "个并发");                    try {                        Thread.sleep((long)(Math.random()*10000));                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println("线程" + Thread.currentThread().getName() +                             "即将离开");                                        sp.release();                    //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元                    System.out.println("线程" + Thread.currentThread().getName() +                             "已离开,当前已有" + (3-sp.availablePermits()) + "个并发");                                    }            };            service.execute(runnable);                    }    }}

 

 

单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了 "锁",再由另外一个线程释放"锁",这可应用于死锁恢复的一些场合。

 

java5 的CyclicBarrier同步工具

/** * 表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面, * 这就好比整个公司的人员利用周末时间集体郊游一样,先各自从家出发到公司集合后, * 再同时出发到公园游玩,在指定地点集合后再同时开始就餐,…。 * @author Administrator * */public class CyclicBarrierTest {    public static void main(String[] args) {        ExecutorService threadPool = Executors.newCachedThreadPool();        final CyclicBarrier cb = new CyclicBarrier(3);        for (int i = 0; i < 3; i++) {            Runnable runnable = new Runnable() {                public void run() {                    try {                        Thread.sleep((long) (Math.random() * 10000));                        System.out.println("线程"+ Thread.currentThread().getName()                                        + "即将到达集合点1,当前已有 "+(cb.getNumberWaiting()+1) +"个已经到达,"+(cb.getNumberWaiting() == 2?"都到齐了,继续走啊":"正在等待"));                        cb.await();                                                Thread.sleep((long) (Math.random() * 10000));                        System.out.println("线程"+ Thread.currentThread().getName()                                + "即将到达集合点2,当前已有 "+(cb.getNumberWaiting()+1) +"个已经到达,"+(cb.getNumberWaiting() == 2?"都到齐了,继续走啊":"正在等待"));                        cb.await();                                                Thread.sleep((long) (Math.random() * 10000));                        System.out.println("线程"+ Thread.currentThread().getName()                                + "即将到达集合点3,当前已有 "+(cb.getNumberWaiting()+1) +"个已经到达,"+(cb.getNumberWaiting() == 2?"都到齐了,继续走啊":"正在等待"));                        cb.await();                    } catch (Exception e) {                        // TODO: handle exception                    }                }            };            threadPool.execute(runnable);        }        threadPool.shutdown();    }}

 

 

 

java5的CountDownLatch同步工具

  CountDownLatch : 闭锁,在完成某些运算时,只有其他所有线程的运算全部完成,当前运算才继续执行

  CountDownLatch应用1:比如要统计5个线程并发的运行时间,即线程的开始时间与最后一个线程的运行结束时间的间隔时间。

  

package com.java.juc;import java.util.concurrent.CountDownLatch;public class TestCountDownLatch2 {    public static void main(String[] args) {        CountDownLatch latch = new CountDownLatch(5);        LatchDemo2 ld = new LatchDemo2(latch);                long start = System.currentTimeMillis();        for(int i = 0;i<5;i++){            new Thread(ld).start();        }        try {            latch.await();   //先执行完成的线程需要等待还没有执行完的线程        } catch (InterruptedException e) {            e.printStackTrace();        }                long end  = System.currentTimeMillis();        System.out.println("cost: "+ (end - start));    }}class LatchDemo2 implements Runnable{    private CountDownLatch latch;        public LatchDemo2(CountDownLatch latch) {        this.latch = latch;    }        @Override    public void run() {        try {            synchronized(this){                for(int i = 0;i<50000;i++){  //找出50000以内的所有偶数                    if(i % 2 == 0){                        System.out.println(i);                    }                }            }        } finally{            latch.countDown();   //为了让这一句一定执行可以放在finally中        }    }}

 

 

 

  还可以应用于计算所有种类商品的平均销售总和,平均销售时间等,如果使用单线程计算效率非常低,相当于是串行计算。可以使用并行计算,按照商品种类进行区分并行的计算。可以将最终的每个线程的计算结果在进行汇总,可以得出最终的的总的销售数据,这就可以使用CountDownLatch进行操作,可以大幅度提高效率。(京东)

 

应用:运动员跑步比赛,得到最终的排名需要在所有运动员都完成之后,公布最终的结果。

/** * 犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减一, * 当计数器到达0时,则所有等待者或单个等待者开始执行。 * 可以实现一个人(也可以是多个人)等待其他所有人都来通知他,可以实现一个人通知多个人的效果, * 类似裁判一声口令,运动员同时开始奔跑,或者所有运动员都跑到 * 终点后裁判才可以公布结果。还可以实现一个计划需要多个领导都签字后 * 才能继续向下实施的情况 * @author Administrator * */public class CountDownLetchTest {    public static void main(String[] args) {        ExecutorService executorService = Executors.newCachedThreadPool();        final CountDownLatch cdOrder = new CountDownLatch(1); //计数器初始值 1        final CountDownLatch cdAnswer = new CountDownLatch(3);        for(int i = 0;i<3;i++){            Runnable runnable = new Runnable() {                                @Override                public void run() {                    try {                        System.out.println("线程"+Thread.currentThread().getName()                                +"正准备接受命令");                        cdOrder.await();                        System.out.println("线程"+Thread.currentThread().getName()                                +"已接受命令");                        Thread.sleep((long)(Math.random()*10000));                        System.out.println("线程"+Thread.currentThread().getName()                                +"回应命令处理结果");                        cdAnswer.countDown();                    } catch (Exception e) {                        // TODO: handle exception                    }                }            };            executorService.execute(runnable);        }        try {            Thread.sleep((long)(Math.random()*10000));            System.out.println("线程"+Thread.currentThread().getName()                    +"即将发布命令");            cdOrder.countDown();  //计数器数值减 1            System.out.println("线程"+Thread.currentThread().getName()                    +"已发送命令,正在等待结果");            cdAnswer.await();            System.out.println("线程"+Thread.currentThread().getName()                    +"已收到所有响应结果");        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        executorService.shutdown();    }}

 java 中CycliBarriar 和 CountDownLatch 有什么区别?

  这两个的区别是CyclicBarrier 可以重复使用已经通过的障碍,而 CountdownLatch 不能重复使用。

 

 

java5的Exchanger同步工具

/** * 用于实现两个人之间的数据交换,每个人在完成一定的事物后想与对方交换数据,第一个先拿出数据的人将 * 一直等待第二个人拿着数据到来时,才能彼此交换数据。 * @author Administrator * */public class ExchangerTest {    public static void main(String[] args) {        ExecutorService executorService = Executors.newCachedThreadPool();        final Exchanger exchanger = new Exchanger();        executorService.execute(new Runnable() {            @Override            public void run() {                try {                    String data1 = "aaa";                    System.out.println("线程" + Thread.currentThread().getName()                            + "正在把数据" + data1 + "换出去");                    Thread.sleep((long) (Math.random() * 10000));                    String data2 = (String) exchanger.exchange(data1);                    System.out.println("线程" + Thread.currentThread().getName()                            + "换回的数据为 " + data2);                } catch (Exception e) {                    // TODO: handle exception                }            }        });        executorService.execute(new Runnable() {            @Override            public void run() {                try {                    String data1 = "bbb";                    System.out.println("线程" + Thread.currentThread().getName()                            + "正在把数据" + data1 + "换出去");                    Thread.sleep((long) (Math.random() * 10000));                    String data2 = (String) exchanger.exchange(data1);                    System.out.println("线程" + Thread.currentThread().getName()                            + "换回的数据为 " + data2);                } catch (Exception e) {                    // TODO: handle exception                }            }        });    }}

 

打印结果为:

线程 pool-1-thread-1正把数据 aaa 换出去

线程 pool-1-thread-2正把数据 bbb 换出去

线程 pool-1-thread-2换回的数据为 aaa

线程 pool-1-thread-1换回的数据为 bbb

 

 

 

 

 

 

转载于:https://www.cnblogs.com/wq3435/p/6037082.html

转载地址:https://blog.csdn.net/ankan7400/article/details/102088974 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Java多线程与并发库高级应用-Callable与Future的应用
下一篇:Java多线程与并发库高级应用-线程池

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月19日 08时58分29秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章