在学习操作系统的时候,我们就接触了生产者与消费者,在Java多线程学习过程中、以及面试中也会常有涉及,在这里进行一下简单的总结。
首先,Java提供两种基本的多线程实现方式:
1、继承Thread类;2、实现Runnable接口;
另外:3、实现Callable<>接口,配合FutureTask类,用Thread类启动,Callable接口的call()方法带返回值(因为1和2线程执行是没有返回值的,所以出了这么个东东);
class Run implements Callable<String> {
private String date = "xiaoma";
@Override public String call() throws Exception {
return date;
}
}
public class RunTest {
public static void main(String[] args) {
Run run = new Run();
FutureTask future = new FutureTask(run);
future.run();
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
采用继承Thread类方式:
- 1 优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
- 2 缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。除此之外,继承Thread方式启动多线程不能够很好的体现数据共享。
采用实现Runnable接口方式:
- 1 优点: 线程类只是实现了Runnable接口,还可以继承其他的类。除此之外,线程对象可以同时被多个线程共享,所以非常适合多线程来处理同一份资源的情况,能够很好的体现数据共享。
- 2 缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
下面切入正题,Java实现生产者与消费者的同步,直接上代码:
1、操作对象
class Info {
private String title;
private String content;
private boolean flag = true;// flag==true,表示可生产,不可消费。falg=false,表示可消费,不可生产。
public synchronized void set(String title, String content) {
if (this.flag == false) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.title = title;
this.content = content;
this.flag = false;
this.notify();
}
public synchronized void get() {
if (this.flag == true) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title + " - " + this.content);
this.flag = true;
this.notify();
}
}
2、生产者
class Producer implements Runnable {
private Info info;
public Producer(Info info) {
this.info = info;
}
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
this.info.set("JAVA" + i, "最好的语言");
} else {
this.info.set("我有壶" + i, "你有酒吗?");
}
}
}
}
3、消费者
class Customer implements Runnable {
private Info info;
public Customer(Info info) {
this.info = info;
}
public void run() {
for (int i = 0; i < 100; i++) {
this.info.get();
}
}
}
4、测试类
public class ThreadDemo {
public static void main(String[] args) {
Info info = new Info();
new Thread(new Producer(info)).start();
new Thread(new Customer(info)).start();
}
}
大功告成,之所以用实现Runnable接口的方式实现是因为上面提到的:“数据共享”。