java并发编程学习3--线程通信练习

来源:互联网 发布:网络最污内涵词语 编辑:程序博客网 时间:2024/06/07 17:16
【问题的描述: 启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. 接着再由线程1打印16,17,18,19,20....以此类推, 直到打印到75. 程序的输出结果应该为: 线程1: 1 线程1: 2 线程1: 3 线程1: 4 线程1: 5 线程2: 6 线程2: 7 线程2: 8 线程2: 9 线程2: 10 ... 线程3: 71 线程3: 72 线程3: 73 线程3: 74 线程3: 75
import java.util.ArrayList;import java.util.List;/** * Created by ibm on 2017/8/8. */public class ClassicTest {    //使用原始的synchornized object.wait() object.notify()    public static void main(String[] args) {        //定义线程组        List<MyThread> threadGroups = new ArrayList<>();        Counter counter = new Counter();        MyThread t1 = new MyThread(1,"一",counter,threadGroups);        MyThread t2 = new MyThread(2,"二",counter,threadGroups);        MyThread t3 = new MyThread(2,"三",counter,threadGroups);        threadGroups.add(t1);        threadGroups.add(t2);        threadGroups.add(t3);        new Thread(t1).start();        new Thread(t2).start();        new Thread(t3).start();    }}class MyThread implements Runnable{    //线程运行状态 1马上执行,2阻塞    public int status;    //线程名字    public String name;    //计数器    public Counter counter;    //线程组    public List<MyThread> threads = new ArrayList<>();    public MyThread(int status,String name,Counter counter,List<MyThread> threads){        this.status = status;        this.name = name;        this.counter = counter;        this.threads = threads;    }    @Override    public void run() {        System.out.println(name + " GET " + status);        synchronized (counter){            while (!counter.isEnd()){                //判断是否该自己执行,切记使用while,因为如果在循环的等待过程中status有所变化,这里需要再次判断                while (status != 1){                    try {                        counter.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                for(int i = 0;i < 5 ;i ++){                    System.out.println(name + ":" + counter.get());                    counter.increase();                }                //状态进入阻塞状态,并设置下一个可以运行的线程                status = 2;                setNext();
                counter.notifyAll();                System.out.println("----");            }        }    }    void setNext(){        //当前线程在线程组的索引        int index = 0;        for(index = 0;index < threads.size();index++){            if(name.equals(threads.get(index).name)){                break;            }        }        if(index == (threads.size() - 1)){            threads.get(0).status = 1;        }else {            threads.get(index + 1).status = 1;        }    }}class Counter{    int num = 1;    int end = 75;    public int get(){        return num;    }    public void increase(){        if(isEnd()){            System.out.println("num超过限制");            return;        }        num++;    }    public boolean isEnd(){        if(num >= end){            return true;        }        return false;    }}
【后面两种解法来源网络:
1.使用synchronized关键字:
/** * Created by ibm on 2017/8/11. */public class ClassicTest1  {    // n为即将打印的数字    private static int n = 1;    // state=1表示将由线程1打印数字, state=2表示将由线程2打印数字, state=3表示将由线程3打印数字    private static int state = 1;    public static void main(String[] args) {        final ClassicTest1 pn = new ClassicTest1();        new Thread(new Runnable() {            public void run() {                // 3个线程打印75个数字, 单个线程每次打印5个连续数字, 因此每个线程只需执行5次打印任务. 3*5*5=75                for (int i = 0; i < 5; i++) {                    // 3个线程都使用pn对象做锁, 以保证每个交替期间只有一个线程在打印                    synchronized (pn) {                        // 如果state!=1, 说明此时尚未轮到线程1打印, 线程1将调用pn的wait()方法, 直到下次被唤醒                        while (state != 1)                            try {                                pn.wait();                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        // 当state=1时, 轮到线程1打印5次数字                        for (int j = 0; j < 5; j++) {                            // 打印一次后n自增                            System.out.println(Thread.currentThread().getName()                                    + ": " + n++);                        }                        System.out.println();                        // 线程1打印完成后, 将state赋值为2, 表示接下来将轮到线程2打印                        state = 2;                        // notifyAll()方法唤醒在pn上wait的线程2和线程3, 同时线程1将退出同步代码块, 释放pn锁.                        // 因此3个线程将再次竞争pn锁                        // 假如线程1或线程3竞争到资源, 由于state不为1或3, 线程1或线程3将很快再次wait, 释放出刚到手的pn锁.                        // 只有线程2可以通过state判定, 所以线程2一定是执行下次打印任务的线程.                        // 对于线程2来说, 获得锁的道路也许是曲折的, 但前途一定是光明的.                        pn.notifyAll();                    }                }            }        }, "线程1").start();        new Thread(new Runnable() {            public void run() {                for (int i = 0; i < 5; i++) {                    synchronized (pn) {                        while (state != 2)                            try {                                pn.wait();                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        for (int j = 0; j < 5; j++) {                            System.out.println(Thread.currentThread().getName()                                    + ": " + n++);                        }                        System.out.println();                        state = 3;                        pn.notifyAll();                    }                }            }        }, "线程2").start();        new Thread(new Runnable() {            public void run() {                for (int i = 0; i < 5; i++) {                    synchronized (pn) {                        while (state != 3)                            try {                                pn.wait();                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        for (int j = 0; j < 5; j++) {                            System.out.println(Thread.currentThread().getName()                                    + ": " + n++);                        }                        System.out.println();                        state = 1;                        pn.notifyAll();                    }                }            }        }, "线程3").start();    }}

2.使用condition与lock
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;/** * Created by ibm on 2017/8/8. */public class ClassicTest2 implements Runnable {    private int state = 1;    private int n = 1;    // 使用lock做锁    private ReentrantLock lock = new ReentrantLock();    // 获得lock锁的3个分支条件    private Condition c1 = lock.newCondition();    private Condition c2 = lock.newCondition();    private Condition c3 = lock.newCondition();    @Override    public void run() {        new Thread(new Runnable() {            public void run() {                for (int i = 0; i < 5; i++) {                    try {                        // 线程1获得lock锁后, 其他线程将无法进入需要lock锁的代码块.                        // 在lock.lock()和lock.unlock()之间的代码相当于使用了synchronized(lock){}                        lock.lock();                        while (state != 1)                            try {                                // 线程1竞争到了lock, 但是发现state不为1, 说明此时还未轮到线程1打印.                                // 因此线程1将在c1上wait                                // 与解法一不同的是, 三个线程并非在同一个对象上wait, 也不由同一个对象唤醒                                c1.await();                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        // 如果线程1竞争到了lock, 也通过了state判定, 将执行打印任务                        for (int j = 0; j < 5; j++) {                            System.out.println(Thread.currentThread().getName()                                    + ": " + n++);                        }                        System.out.println();                        // 打印完成后将state赋值为2, 表示下一次的打印任务将由线程2执行                        state = 2;                        // 唤醒在c2分支上wait的线程2                        c2.signal();                    } finally {                        // 打印任务执行完成后需要确保锁被释放, 因此将释放锁的代码放在finally中                        lock.unlock();                    }                }            }        }, "线程1").start();        new Thread(new Runnable() {            public void run() {                for (int i = 0; i < 5; i++) {                    try {                        lock.lock();                        while (state != 2)                            try {                                c2.await();                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        for (int j = 0; j < 5; j++) {                            System.out.println(Thread.currentThread().getName()                                    + ": " + n++);                        }                        System.out.println();                        state = 3;                        c3.signal();                    } finally {                        lock.unlock();                    }                }            }        }, "线程2").start();        new Thread(new Runnable() {            public void run() {                for (int i = 0; i < 5; i++) {                    try {                        lock.lock();                        while (state != 3)                            try {                                c3.await();                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        for (int j = 0; j < 5; j++) {                            System.out.println(Thread.currentThread().getName()                                    + ": " + n++);                        }                        System.out.println();                        state = 1;                        c1.signal();                    } finally {                        lock.unlock();                    }                }            }        }, "线程3").start();    }    public static void main(String[] args) {        new ClassicTest2().run();    }}

 
原创粉丝点击