JAVA Review-应用程序开发-JAVA多线程-线程通信
前言
前面一节中我们学习如何在多线程中确保共享数据的线程安全。本节我们将学一下如何实现多线程间的通信。
首先在JAVA中有很多方式实现多线程间的通信。本节将着重讲学习如何使用synchronized+notify+wait+flag的方式来实现多线程的通信。
首先我们先了解一下一些概念:
- wait()
* 令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问
- notify()
* 唤醒正在排队等待同步资源的线程中优先级最高者结束等待。
- notifyAll ()
* 唤醒正在排队等待资源的所有线程结束等待。
wait()、notify()、notifyAll () 只能在synchronized修饰的代码块或者方法中使用!,是多线程通信的独有方法。
示例
我们将通过一些例子来学习java多线程通信。
生产者与消费者
生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下, 如果店中有产品了再通知消费者来取走产品。class Clerk{ //店员
int product;
public synchronized void addProduct(){
//生产产品
if(product >= 20){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
product++;
System.out.println(Thread.currentThread().getName() + ":生产了第" + product + "个产品");
notifyAll();
}
}
public synchronized void consumeProduct(){
//消费产品
if(product <= 0){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
System.out.println(Thread.currentThread().getName() + ":消费了第" + product + "个产品");
product--;
notifyAll();
}
}
}
class Producer implements Runnable{ //生产者
Clerk clerk;
public Producer(Clerk clerk){
this.clerk = clerk;
}
public void run(){
System.out.println("生产者开始生产产品");
while(true){
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.addProduct();
}
}
}
class Consumer implements Runnable{ //消费者
Clerk clerk;
public Consumer(Clerk clerk){
this.clerk = clerk;
}
public void run(){
System.out.println("消费者消费产品");
while(true){
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.consumeProduct();
}
}
}
public class produceAndConsumer{
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p1 = new Producer(clerk);
Consumer c1 = new Consumer(clerk);
Thread t1 = new Thread(p1);//一个生产者的线程
Thread t2 = new Thread(c1);//一个消费者的线程
t1.setName("生产者1");
t2.setName("消费者1");
t1.start();
t2.start();
}
}
程序设计思路:在上例中,生产者和消费者只负责生产产品和消费产品,至于什么时候(库存>=0)该生产什么时候(0<库存<20)可以消费取决于店员,因而店员将是统一调度生产者生产和消费者消费的关键所在。
两个打印机交替打印
- 两个打印机交替打印1-100内的整数
代码示例
```
package coreJavaReview.thread;
class PrintNum implements Runnable {
int num = 1;
Object obj = new Object();
public void run() {
while (true) {
synchronized (obj) {
obj.notify();
if (num <= 100) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":"
+ num);
num++;
} else {
break;
}
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class ThreadCommunicationCross {
public static void main(String[] args) {
PrintNum p = new PrintNum();
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
t1.setName("A");
t2.setName("B");
t1.start();
t2.start();
}
}
```
程序设计思路:两台打印机交替打印,每次只能有一台机器在打印,也需要要求是多线程安全的,此时要求获得打印资格的打印机必须在打印完毕之后放弃(放弃CPU资源)打印资格。
多线程按照顺序循环地执行
- 场景说明
开启三个线程顺序地执行输出1-150整数。,每个线程持续输出连续的5个整数。 代码示例
package coreJavaReview.thread;
public class ThreadCrossCommunicationTest {
public static void main(String[] args) {
Object obj = new Object();
for(int i=1;i<=3;i++){
//传入对象锁 和 i值
new Thread(new MyThread2(obj,i), "线程"+i).start();
}
}
}
class MyThread2 implements Runnable{
private static int i = 0;//打印的值 1-75
private static int count=0;//计数 三次一轮回
private Object obj;
private int n;//接参 i值
public MyThread2(Object obj,int n) {
this.obj=obj;
this.n = n;
}
- 场景说明
@Override
public void run() {
synchronized (obj) {
while(i<150){
//i++ 在代码块 所以到74就可以了
obj.notifyAll();//唤醒所有线程
if(count%3!=(n-1)){ //找出下一个线程 不正确的线程等待
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
i++;
System.out.println(Thread.currentThread().getName()+": "+i);
if(i%5 == 0){ //打印了五次后 此线程让出资源,等待
try {
count++; //count是static修饰 ,为了共享
System.out.println();
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
还没有评论,来说两句吧...