JAVA多线程通信

一、两个线程间的通信

1.什么时候需要通信

多个线程并发执行时,在默认情况下CPU是随机切换线程的,如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印

2.如何通信

如果希望线程等待,就调用wait()

如果希望唤醒等待的线程,就调用notify()

这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用

3.代码

class Printer {
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized(this) {
			if(flag != 1) {
				this.wait();				//当前线程等待
			}
			System.out.print("1");
			System.out.print("2");
			System.out.print("3");
			System.out.print("4");
			System.out.print("5");
			System.out.print("\r\n");
			flag = 2;
			this.notify();				//随机唤醒单个等待的线程
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			if(flag != 2) {
				this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("\r\n");
			flag = 1;
			this.notify();
		}
	}
}

二、三个及以上线程间的通信

1.如何通信

notify()方法是随机唤醒一个线程,notifyAll()方法是唤醒所有线程

JDK5之前无法唤醒指定的一个线程,如果多个线程之间通信,需要使用notifyAll()通知所有线程,用while来反复判断条件

2.代码

class Printer2 {
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized(this) {
			while(flag != 1) {
				this.wait();				
			}
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 2;
			this.notifyAll();
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			while(flag != 2) {
				this.wait();					//线程2在此等待
			}
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 3;
			this.notifyAll();
		}
	}
	
	public void print3() throws InterruptedException {
		synchronized(this) {
			while(flag != 3) {
				this.wait();	//线程3在此等待,if语句是在哪里等待,就在哪里起来
								//while循环是循环判断,每次都会判断标记
			}
			System.out.print("i");
			System.out.print("t");
			System.out.print("h");
			System.out.print("e");
			System.out.print("i");
			System.out.print("m");
			System.out.print("a");
			System.out.print("\r\n");
			flag = 1;
			this.notifyAll();
		}
	}
}

注:

  • 1.在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法
  • 2.为什么wait方法和notify方法定义在Object这类中?

          因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在Object这个类中

  • 3.sleep方法和wait方法的区别?

          sleep方法必须传入参数,参数就是时间,时间到了自动醒来

          wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待

          sleep方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁睡

          wait方法在同步函数或者同步代码块中,释放锁

三、JDK1.5的新特性互斥锁

1.同步

使用ReentrantLock类的lock()和unlock()方法进行同步

2.通信

使用ReentrantLock类的newCondition()方法可以获取Condition对象

需要等待的时候使用Condition的await()方法,唤醒的时候用signal()方法

不同的线程使用不同的Condition,这样就能区分唤醒的时候找哪个线程了

3.代码

class Printer3 {
	private ReentrantLock r = new ReentrantLock();
	private Condition c1 = r.newCondition();
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();
	
	private int flag = 1;
	public void print1() throws InterruptedException {
		r.lock();								//获取锁
			if(flag != 1) {
				c1.await();
			}
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 2;
			c2.signal();
		r.unlock();								//释放锁
	}
	
	public void print2() throws InterruptedException {
		r.lock();
			if(flag != 2) {
				c2.await();
			}
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 3;
			c3.signal();
		r.unlock();
	}
	
	public void print3() throws InterruptedException {
		r.lock();
			if(flag != 3) {
				c3.await();
			}
			System.out.print("i");
			System.out.print("t");
			System.out.print("h");
			System.out.print("e");
			System.out.print("i");
			System.out.print("m");
			System.out.print("a");
			System.out.print("\r\n");
			flag = 1;
			c1.signal();
		r.unlock();
	}
}

 

你可能感兴趣的:(JAVA基础)