生产者和消费者synchronized版
package demo1;
/**
* 题目:现在两个线程,可以操作初始值为0的一个变量
* 实现一个线程对该变量 + 1,一个线程对该变量 -1
* 实现交替10次
*
* 诀窍:
* 1. 高内聚低耦合的前提下,线程操作资源类
* 2. 判断 、干活、通知
*/
public class Test01 {
public static void main(String[] args) {
Data data = new Data();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=40;i++){
try {
data.increament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=40;i++){
try {
data.decreament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"B").start();
}
}
class Data{
private int num=0;
//让变量+1
public synchronized void increament() throws InterruptedException {
//判断该不该这个线程做
if (num!=0){
this.wait();
}
//干活
num++;
System.out.println(Thread.currentThread().getName()+"\t"+num);
//通知
this.notify();
}
//让变量-1
public synchronized void decreament() throws InterruptedException {
if (num==0){
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"\t"+num);
this.notify();
}
}
问题升级:防止虚假唤醒,4个线程,两个加,两个减
- 重点if和while
以下代码增加了两个线程,把if换成了while不然会出现虚假唤醒现象
package demo1;
/**
* 题目:现在四个线程,可以操作初始值为0的一个变量
* 实现一个线程对该变量 + 1,一个线程对该变量 -1
* 实现交替10次
*
* 诀窍:
* 1. 高内聚低耦合的前提下,线程操作资源类
* 2. 判断 、干活、通知
*/
public class Test01 {
public static void main(String[] args) {
Data data = new Data();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
try {
data.increament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
try {
data.decreament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
try {
data.increament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"C").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
try {
data.decreament();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"D").start();
}
}
class Data{
private int num=0;
//让变量+1
public synchronized void increament() throws InterruptedException {
//判断该不该这个线程做
while (num!=0){
this.wait();
}
//干活
num++;
System.out.println(Thread.currentThread().getName()+"\t"+num);
//通知
this.notify();
}
//让变量-1
public synchronized void decreament() throws InterruptedException {
while (num==0){
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"\t"+num);
this.notify();
}
}
生产者和消费者新版Lock版
闲聊常见笔试题:手写单例模式、手写冒泡排序、手写生产者消费者
package demo1;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 题目:现在四个线程,可以操作初始值为0的一个变量
* 实现两个线程对该变量 + 1,两个线程对该变量 -1
* 实现交替10次
* <p>
* 诀窍:
* 1. 高内聚低耦合的前提下,线程操作资源类
* 2. 判断 、干活、通知
* 3. 多线程交互中,必须要防止多线程的虚假唤醒,也即(判断不能用if,只能用while)
*/
public class Test01 {
public static void main(String[] args) {
Data data = new Data();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
data.increament();
}
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
data.decreament();
}
}
},"B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
data.increament();
}
}
},"C").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=10;i++){
data.decreament();
}
}
},"D").start();
}
}
class Data{
private int num=0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
//让变量+1
public void increament() {
//判断该不该这个线程做
lock.lock();
try {
while (num!=0){
condition.await();
}
//干活
num++;
System.out.println(Thread.currentThread().getName()+"\t"+num);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//通知
lock.unlock();
}
}
//让变量-1
public void decreament(){
lock.lock();
try {
//判断该不该这个线程做
while (num==0){
condition.await();
}
//干活
num--;
System.out.println(Thread.currentThread().getName()+"\t"+num);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//通知
lock.unlock();
}
}
}