线程间的通讯

线程通讯需要使用到的三个方法: wait()、notify()与notifyAll()。该三个方法不在Thread类中定义,而是在Object类中
wait() 方法:让当前线程挂起并放弃cpu使用权,同步资源,使别的线程可以访问并修改同步资源,而当前线程排队等待,直到被唤醒后才能再次获取cpu使用权和同步资源的访问。
notify()方法: 唤醒正在排队等待同步资源的线程中优先级最高者结束等待,得到cpu的使用权和对同步资源的访问。
notifyAll()方法:唤醒正在排队等待同步资源的所有线程结束等待,竞争资源。
注意:这三个方法只有在同步代码块或同步方法中使用,在其他地方使用会报错 java.lang.IllegalArgumentException 异常
案例分析:
    1、创建三个线程(A,B,C),让该三个线程交替循环10次打印字母'A','B','C',最终的结果为:ABCABCABCABCABC...
继承Thread类的方式:
package org.xyz.java.thread.demo04;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 案例练习  - 使用继承Thread的方式
 * 	创建三个线程(A,B,C),让该三个线程交替循环10次打印字母'A','B','C',最终的结果为:ABCABCABCABCABC...
 * @author kevin.chen
 *
 */
public class PrintLock {
        public static void main(String[] args) throws Exception {
                At a = new At();
                Bt b = new Bt();
                Ct c = new Ct();
                
                a.setName("甲");
                b.setName("乙");
                c.setName("丙");
                
                a.start();
                b.start();
                c.start();
                
        }
        
        
        // 使用lock锁+condition的方式:
        private static Lock lock = new ReentrantLock();
        private static Condition aCond = lock.newCondition();
        private static Condition bCond = lock.newCondition();
        private static Condition cCond = lock.newCondition();
        private static int count = 0;
        
        static class At extends Thread {
                @Override
                public void run() {
                        for(int i = 0;i < 10; i++) {
                                try {
                                        lock.lock();
                                        try {
                                                while(count % 3 != 0) { // 这里是不等条件
                                                        aCond.await(); // 相当于wait   让该线程等待
                                                }
                                                System.out.println(Thread.currentThread().getName() + ": A");
                                                count ++;
                                                Thread.sleep(100);
                                                bCond.signal(); // 相当于notify  唤醒下一个线程
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                        }
                                } finally {
                                        lock.unlock();
                                }
                        }
                }
        }
        
        static class Bt extends Thread {
                @Override
                public void run() {
                        for(int i = 0;i < 10; i++) {
                                try {
                                        lock.lock();
                                        try {
                                                while(count % 3 != 1) { // 这里是不等条件
                                                        bCond.await(); // 相当于wait   让该线程等待
                                                }
                                                System.out.println(Thread.currentThread().getName() + ": B");
                                                count ++;
                                                Thread.sleep(100);
                                                cCond.signal(); // 相当于notify  唤醒下一个线程
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                        }
                                } finally {
                                        lock.unlock();
                                }
                        }
                }
        }
        
        static class Ct extends Thread {
                @Override
                public void run() {
                        for(int i = 0;i < 10; i++) {
                                try {
                                        lock.lock();
                                        try {
                                                while(count % 3 != 2) { // 这里是不等条件
                                                        cCond.await(); // 相当于wait   让该线程等待
                                                }
                                                System.out.println(Thread.currentThread().getName() + ": C");
                                                count ++;
                                                Thread.sleep(100);
                                                aCond.signal(); // 相当于notify  唤醒下一个线程
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                        }
                                } finally {
                                        lock.unlock();
                                }
                        }
                }
        }
        
}
继承+同步的方式:该方式没有用到线程的通讯方法,属于变种(不推荐)
package org.xyz.java.thread.demo04;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 案例练习  - 使用继承Thread的方式
 * 	创建三个线程(A,B,C),让该三个线程交替循环10次打印字母'A','B','C',最终的结果为:ABCABCABCABCABC...
 * @author kevin.chen
 *
 */
public class PrintThread {
        public static void main(String[] args) throws Exception {
                At a = new At();
                Bt b = new Bt();
                Ct c = new Ct();
                
                a.setName("甲");
                b.setName("乙");
                c.setName("丙");
                
                a.start();
                Thread.sleep(100); // 此处是为了保证第一次的顺序为ABC
                b.start();
                Thread.sleep(100);
                c.start();
                
        }
        
//	// 使用synchronized同步的方式
//	private static int count = 0;
//	
//	static class At extends Thread {
//		@Override
//		public void run() {
//			for(int i = 0;i < 10; ) {
//				synchronized(PrintThread.class) { // 这里必须使用同一类对象锁,不能使用this/At.class
//					while(count % 3 == 0) {
//						System.out.println(Thread.currentThread().getName() + ": A");
//						count ++;
//						i ++;
//						try {
//							Thread.sleep(100);
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}
//					}
//				}
//			}
//		}
//	}
//	
//	static class Bt extends Thread {
//		@Override
//		public void run() {
//			for(int i = 0;i < 10;) {
//				synchronized(PrintThread.class) { // 这里必须使用同一类对象锁,不能使用this/At.class
//					while(count % 3 == 1) {
//						System.out.println(Thread.currentThread().getName() + ": B");
//						count ++;
//						i++;
//						try {
//							Thread.sleep(100);
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}
//					}
//				}
//			}
//		}
//	}
//	
//	static class Ct extends Thread {
//		@Override
//		public void run() {
//			for(int i = 0;i < 10;) {
//				synchronized(PrintThread.class) { // 这里必须使用同一类对象锁,不能使用this/At.class
//					while(count % 3 == 2) {
//						System.out.println(Thread.currentThread().getName() + ": C");
//						count ++;
//						i++;
//						try {
//							Thread.sleep(100);
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}
//					}
//				}
//			}
//		}
//	}
        
        // 使用lock锁的方式:
        private static Lock lock = new ReentrantLock();
        private static int count = 0;
        
        static class At extends Thread {
                @Override
                public void run() {
                        for(int i = 0;i < 10;) { // 此处的i++ 操作一定要放在while循环中
                                try {
                                        lock.lock();
                                        while(count % 3 == 0) {
                                                System.out.println(Thread.currentThread().getName() + ": A");
                                                count ++;
                                                i ++;
                                                try {
                                                        Thread.sleep(100);
                                                } catch (InterruptedException e) {
                                                        e.printStackTrace();
                                                }
                                        }
                                } finally {
                                        lock.unlock();
                                }
                        }
                        
                        // 错误的写法,注意for循环和try的位置,错误的写法线程无法执行,这个问题记录下
//			try {
//				for(int i = 0;i < 10; ) { // 此处的i++ 操作一定要放在while循环中
//					lock.lock();
//					while(count % 3 == 0) {
//						System.out.println(Thread.currentThread().getName() + ": A");
//						count ++;
//						i ++;
//						try {
//							Thread.sleep(100);
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}
//					}
//				}
//			} finally {
//				lock.unlock();
//			}
                }
        }
        
        static class Bt extends Thread {
                @Override
                public void run() {
                        for(int i = 0;i < 10;) { // 此处的i++ 操作一定要放在while循环中
                                try {
                                        lock.lock();
                                        while(count % 3 == 1) {
                                                System.out.println(Thread.currentThread().getName() + ": B");
                                                count ++;
                                                i ++;
                                                try {
                                                        Thread.sleep(100);
                                                } catch (InterruptedException e) {
                                                        e.printStackTrace();
                                                }
                                        }
                                } finally {
                                        lock.unlock();
                                }
                        }
                }
        }
        
        static class Ct extends Thread {
                @Override
                public void run() {
                        for(int i = 0;i < 10;) { // 此处的i++ 操作一定要放在while循环中
                                try {
                                        lock.lock();
                                        while(count % 3 == 2) {
                                                System.out.println(Thread.currentThread().getName() + ": C");
                                                count ++;
                                                i ++;
                                                try {
                                                        Thread.sleep(100);
                                                } catch (InterruptedException e) {
                                                        e.printStackTrace();
                                                }
                                        }
                                } finally {
                                        lock.unlock();
                                }
                        }
                }
        }
        
}
实现Runnable的方式:
package org.xyz.java.thread.demo04;
/**
 * 案例练习  - 使用实现Runnable的方式
 * 	创建三个线程(A,B,C),让该三个线程交替循环5次打印字母'A','B','C',最终的结果为:ABCABCABCABCABC...
 * @author kevin.chen
 *
 */
public class PrintRunnable {
        public static void main(String[] args) throws Exception {
                int count = 5;
                Object a = new Object(); // a对象锁
                Object b = new Object(); // b对象锁
                Object c = new Object(); // c对象锁
                
                Print p1 = new Print(count,c,a,"A");
                Print p2 = new Print(count,a,b,"B");
                Print p3 = new Print(count,b,c,"C");
                
                Thread ta = new Thread(p1);
                Thread tb = new Thread(p2);
                Thread tc = new Thread(p3);
                
                ta.setName("甲");
                tb.setName("乙");
                tc.setName("丙");
                
                ta.start();
                Thread.sleep(100); // 此处是为了保证第一次的顺序为ABC
                tb.start();
                Thread.sleep(100);
                tc.start();
                
        }
}
class Print implements Runnable {
        
        private int count; // 循环次数
        private Object prev; // 前一个对象
        private Object self; // 自身对象
        private String content; // 输出内容
        
        public Print(int count,Object prev,Object self,String content) {
                this.count = count;
                this.prev = prev;
                this.self = self;
                this.content = content;
        }
        @Override
        public void run() {
                int num = count * 3;
                while(num > 0) {
                        synchronized(prev) {
                                synchronized(self) {
                                        // 唤醒其他线程
                                        self.notifyAll(); 
                                        try {
                                                Thread.sleep(50);
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                        }
                                        System.out.println(Thread.currentThread().getName() + ":" + content);
//					System.out.print(content);
                                        num --;
                                }
                                try {
                                        if(num == 0) { // 增加这个判断可以保证线程执行完之后能自动退出,如果没有该判断,程序是不会自动退出的
                                                prev.notifyAll();  
                                        }else {
                                                // 当前线程挂起等待
                                                prev.wait();
                                        }
                                } catch (InterruptedException e) {
                                        e.printStackTrace();
                                }
                        }
                }
        }
        
}

运行结果:

:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
甲:A
乙:B
丙:C
使用信号灯来实现
可以看到信号灯的变化情况如下:
初始(A=1,B=0,C=0)—>执行线程A时(A=1,B=0,C=0)—>执行线程B时(A=0,B=1,C=0)—>执行线程C时(A=0,B=0,C=1)—>再执行线程A(A=1,B=0,C=0)… 如此循环。
package org.xyz.java.thread.demo04;
import java.util.concurrent.Semaphore;
public class SemaphoreAbc {
        
        // 初始化线程A的sA中的计数器为1,保证先执行
        private static Semaphore sA = new Semaphore(1);
        // 初始化线程B的sB中的计数器为0
        private static Semaphore sB = new Semaphore(0);
        // 初始化线程C的sC中的计数器为0
        private static Semaphore sC = new Semaphore(0);
    static class ThreadA extends Thread {
        @Override
        public void run() {
                        try {
                                for (int i = 0; i < 10; i++) {
                                        // 线程A 获取信号进行执行,将sA的计数器减1,当sA的计数器减为0时,该线程无法获取到信号,则线程挂起等待
                                        sA.acquire();
                                        System.out.println(Thread.currentThread().getName() + ": A");
                                        // 线程A执行后,将sB的计数器加1
                                        sB.release();
                                }
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
        }
    }
    static class ThreadB extends Thread {
        @Override
        public void run() {
                        try {
                                for (int i = 0; i < 10; i++) {
                                        // 线程B 获取信号进行执行,将sB的计数器减1,当sB的计数器减为0时,该线程无法获取到信号,则线程挂起等待
                                        sB.acquire();
                                        System.out.println(Thread.currentThread().getName() + ": B");
                                        // 线程B执行后,将sC的计数器加1
                                        sC.release();
                                }
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
        }
    }
    static class ThreadC extends Thread {
        @Override
        public void run() {
                        try {
                                for (int i = 0; i < 10; i++) {
                                        // 线程C 获取信号进行执行,将sC的计数器减1,当sC的计数器减为0时,该线程无法获取到信号,则线程挂起等待
                                        sC.acquire();
                                        System.out.println(Thread.currentThread().getName() + ": C");
                                        // 线程C执行后,将sA的计数器加1
                                        sA.release();
                                }
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
        }
    }
    public static void main(String[] args) {
        ThreadA a = new ThreadA();
        ThreadB b = new ThreadB();
        ThreadC c = new ThreadC();
        
        a.setName("甲");
        b.setName("乙");
        c.setName("丙");
        
        a.start();
        b.start();
        c.start();
    }	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值