模拟场景:顾客买车从车库中取车,厂家生产车,车存储在车库中。买家、厂家对同一个车库中的车操作

一、不加同步机制的代码如下:

package com.joysuch.testng.thread;

import java.util.ArrayList;
import java.util.List; import com.joysuch.testng.thread.ThreadDemo1.CarHouse.Car; /**
* @author ning
* 创建于 2017年11月22日上午11:25:29
* //TODO (没有加上同步机制)
*/
public class ThreadDemo1 { /**
* @author ning
* 创建于 2017年11月22日上午11:27:53
* //TODO 卖车的当做生产者线程
*/
public static class CarSeller implements Runnable { private CarHouse carHouse; public CarSeller(CarHouse carHouse){
this.carHouse = carHouse;
} @Override
public void run() {
for (int i = 0; i < 10; i++) {// 当做生产者线程,往仓库里边增加汽车,其实是触发增加汽车
carHouse.put(i);
}
} } /**
* @author ning
* 创建于 2017年11月22日上午11:29:00
* //TODO 购买者当做消费者线程
*/
public static class Consumer implements Runnable { private CarHouse carHouse; public Consumer(CarHouse carHouse){
this.carHouse = carHouse;
} @Override
public void run() {
for (int i = 0; i < 10; i++) {// 当做消费者线程,从仓库里边提取汽车,其实是触发,从仓库里边提取一辆汽车出来
carHouse.get(i);
}
}
} /**
* @author ning
* 创建于 2017年11月22日上午11:30:22
* //TODO 汽车仓库
*/
public static class CarHouse {
/**
* 车库中汽车数量
*/
public Integer carNums = 0; public Integer getCarNums() {
return carNums;
} public void setCarNums(Integer carNums) {
this.carNums = carNums;
} public List<Car> getCarList() {
return carList;
} public void setCarList(List<Car> carList) {
this.carList = carList;
} /**
* 存放汽车的集合
*/
public List<Car> carList = new ArrayList<>(); public int put(int i){
Car car = CarFactory.makeNewCar();
carList.add(car);
carNums++;
System.out.println("生产汽车-" + i + "->车库汽车数量---count = " + carList.size());
return carList.size();
} public int get(int i){
Car car = null;
if(carList.size() > 0){
car = carList.get(carList.size() - 1);
carList.remove(car);
carNums--;
}
System.out.println("消费汽车-" + i + "->车库汽车数量---count = " + carList.size());
return carList.size();
} public static class Car {
public String carName;
public double carPrice; public Car(){} public Car(String carName, Double carPrice){
this.carName = carName;
this.carPrice = carPrice;
} public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public double getCarPrice() {
return carPrice;
}
public void setCarPrice(double carPrice) {
this.carPrice = carPrice;
}
}
} /**
* 采用静态工厂方式创建car对象,这个只是简单模拟,不做设计模式上的过多考究
*/
public static class CarFactory { private CarFactory(){ } public static Car makeNewCar(String carName, Double carPrice){
return new Car(carName, carPrice);
} public static Car makeNewCar() {
return new Car();
}
} /**
* 第一个版本的生产者和消费者线程,没有加上同步机制的演示例子
*
* @param args
*/
public static void main(String[] args) {
CarHouse bigHouse = new CarHouse();
new Thread(new CarSeller(bigHouse)).start();
new Thread(new Consumer(bigHouse)).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(bigHouse.getCarNums());
System.out.println(bigHouse.getCarList().size());
}
}

运行结果产生的错读如下:

消费汽车-0->车库汽车数量---count = 0
消费汽车-1->车库汽车数量---count = 0
消费汽车-2->车库汽车数量---count = 0
消费汽车-3->车库汽车数量---count = 0
消费汽车-4->车库汽车数量---count = 0
消费汽车-5->车库汽车数量---count = 0
消费汽车-6->车库汽车数量---count = 0
消费汽车-7->车库汽车数量---count = 0
消费汽车-8->车库汽车数量---count = 0
消费汽车-9->车库汽车数量---count = 0
生产汽车-0->车库汽车数量---count = 1
生产汽车-1->车库汽车数量---count = 1
生产汽车-2->车库汽车数量---count = 2
生产汽车-3->车库汽车数量---count = 3
生产汽车-4->车库汽车数量---count = 4
生产汽车-5->车库汽车数量---count = 5
生产汽车-6->车库汽车数量---count = 6
生产汽车-7->车库汽车数量---count = 7
生产汽车-8->车库汽车数量---count = 8
生产汽车-9->车库汽车数量---count = 9
9
9

从上面的结果可以看出,在生产了一次汽车之后,车库汽车数量为1,然后生产第2次的时候,车库汽车数量仍为1,显然是不正确的。可能是线程再执行最后一次消费汽车时,还没执行完,第一次的生成汽车就执行了,导致车库汽车数量又从1变成了0。所以第2次执行生成汽车的时候,结果车库数量为1。

二、加上互斥锁

代码如下:

package com.joysuch.testng.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import com.joysuch.testng.thread.ThreadDemo2.CarHouse.Car; /**
* @author ning
* 创建于 2017年11月22日上午11:25:29
* //TODO (加上互斥锁)
*/
public class ThreadDemo2 { /**
* @author ning
* 创建于 2017年11月22日上午11:27:53
* //TODO 卖车的当做生产者线程
*/
public static class CarSeller implements Runnable { private CarHouse carHouse; public CarSeller(CarHouse carHouse){
this.carHouse = carHouse;
} @Override
public void run() {
for (int i = 0; i < 10; i++) {// 当做生产者线程,往仓库里边增加汽车,其实是触发增加汽车
carHouse.put(i);
}
} } /**
* @author ning
* 创建于 2017年11月22日上午11:29:00
* //TODO 购买者当做消费者线程
*/
public static class Consumer implements Runnable { private CarHouse carHouse; public Consumer(CarHouse carHouse){
this.carHouse = carHouse;
} @Override
public void run() {
for (int i = 0; i < 10; i++) {// 当做消费者线程,从仓库里边提取汽车,其实是触发,从仓库里边提取一辆汽车出来
carHouse.get(i);
}
}
} /**
* @author ning
* 创建于 2017年11月22日上午11:30:22
* //TODO 汽车仓库
*/
public static class CarHouse {
/**
* 车库中汽车数量
*/
public Integer carNums = 0; /**
* 存放汽车的集合
*/
public List<Car> carList = new ArrayList<>(); public Integer getCarNums() {
return carNums;
} public void setCarNums(Integer carNums) {
this.carNums = carNums;
} public List<Car> getCarList() {
return carList;
} public void setCarList(List<Car> carList) {
this.carList = carList;
} // 直接增加上synchronized关键字方式,成员方法,锁的是当前bigHouse对象
// 这种锁是互斥锁,方法在同一个时刻,只有一个线程可以访问到里边的代码
/* public synchronized int put(int i) {// 提供给生产者放汽车到仓库的接口
Car car = CarFactory.makeNewCar();
carList.add(car);// 加到仓库中去
carNums++;// 总数增加1
System.out.println("生产汽车-" + i + "->车库汽车数量---count = " + carList.size());
return carList.size();
} public synchronized int get(int i) {// 提供给消费者从这边取汽车接口
Car car = null;
if (carList.size() != 0) {// size不为空才去取车
car = carList.get(carList.size() - 1);// 提取最后一个car
carList.remove(car);// 从从库list中移除掉
carNums--;// 总数减少1
}
System.out.println("消费汽车-" + i + "->车库汽车数量---count = " + carList.size());
return carList.size();
} */ //Lock提供了比synchronized方法和synchronized代码块更广泛的锁定操作,Lock更灵活的结构,有很大的差别,并且可以支持多个Condition对象 Lock是控制多个线程对共享资源进行访问的工具。
//通常,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁, 线程开始访问共享资源之前应先获得Lock对象。
//不过某些锁支持共享资源的并发访问,如:ReadWriteLock(读写锁),在线程安全控制中, 通常使用ReentrantLock(可重入锁)。使用该Lock对象可以显示加锁、释放锁。
final ReentrantLock lock = new ReentrantLock(); public int put(int i){
int size = -100;
//上锁
lock.lock(); try {
Car car = CarFactory.makeNewCar();
carList.add(car);
carNums++;
size = carList.size();
System.out.println("生产汽车-" + i + "->车库汽车数量---count = " + size);
}finally{
//释放锁
lock.unlock();
}
return size;
} public int get(int i){
//上锁
int size = -100;
lock.lock();
try{
Car car = null;
if (carList.size() != 0) {// size不为空才去取车
car = carList.get(carList.size() - 1);// 提取最后一个car
carList.remove(car);// 从车库list中移除掉
carNums--;// 总数减少1
}
size = carList.size();
System.out.println("消费汽车 " + i + "-->车库汽车数量---count = " + size);
}finally{
//释放锁
lock.unlock();
}
return size;
} public static class Car {
public String carName;
public double carPrice; public Car(){} public Car(String carName, Double carPrice){
this.carName = carName;
this.carPrice = carPrice;
} public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public double getCarPrice() {
return carPrice;
}
public void setCarPrice(double carPrice) {
this.carPrice = carPrice;
}
@Override
public String toString() {
return "Car [carName=" + carName + ", carPrice=" + carPrice + "]";
}
}
} /**
* 采用静态工厂方式创建car对象,这个只是简单模拟,不做设计模式上的过多考究
*/
public static class CarFactory { private CarFactory(){ } public static Car makeNewCar(String carName, Double carPrice){
return new Car(carName, carPrice);
} public static Car makeNewCar() {
return new Car();
}
} /**
* 第一个版本的生产者和消费者线程,没有加上同步机制的演示例子
*
* @param args
*/
public static void main(String[] args) {
int x = 0;
//这里为了便于查看测试结果,所以执行了多次
while(x < 50){
CarHouse bigHouse = new CarHouse();
new Thread(new CarSeller(bigHouse)).start();
new Thread(new Consumer(bigHouse)).start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(bigHouse.getCarNums());
System.out.println(bigHouse.getCarList().size());
x++;
}
}
}

鉴于结果太多,就不展示结果代码。

三、采用Object类的wait和notify方法或者notifyAll方法

代码如下:

package com.joysuch.testng.thread;

import java.util.ArrayList;
import java.util.List; import com.joysuch.testng.thread.ThreadDemo3.CarBigHouse.Car; /**
* @ClassName: ThreadDemo3
* @Description: TODO(采用Object类的wait和notify方法或者notifyAll方法(注意notify方法和notifyAll方法区别)
* notify是唤醒其中一个在等待的线程。 notifyAll是唤醒其他全部在等待的线程,但是至于哪个线程可以获得到锁还是要看竞争关系。线程状态:创建、运行、阻塞、销毁状态。(阻塞情况比较多,比如等待数据IO输入,阻塞了。))
* @author ning
* @date 2017年11月22日 上午11:38:09
*
*/
public class ThreadDemo3 { /**
* 姑且卖车的当做是生产者线程
*/
public static class CarSeller implements Runnable { private CarBigHouse bigHouse; public CarSeller(CarBigHouse bigHouse) {
this.bigHouse = bigHouse;
} public void run() {
for (int i = 0; i < 10; i++) {// 当做生产者线程,往仓库里边增加汽车,其实是触发增加汽车
bigHouse.put();
}
} } /**
* 姑且买车的人当做是消费者线程
*/
public static class Consumer implements Runnable { private CarBigHouse bigHouse; public Consumer(CarBigHouse bigHouse) {
this.bigHouse = bigHouse;
} public void run() {
for (int i = 0; i < 10; i++) {// 当做消费者线程,从仓库里边提取汽车,其实是触发,从仓库里边提取一辆汽车出来
bigHouse.get();
}
} } /**
* 这边姑且当做是车子big house放车子的仓库房
*/
public static class CarBigHouse { public int carNums = 0;// 这边是仓库房子中车子的数量总数
public List<Car> carList = new ArrayList<Car>();// 这边模拟用来放汽车的list
public static final int max = 3;// 简单设置下,做下上限设置 private Object lock = new Object();// 采用object的wait和notify方式处理同步问题 public int put() {// 提供给生产者放汽车到仓库的接口
synchronized (lock) {
if (carList.size() == max) {// 达到了上限,不再生产car
try {
System.out.println("生产达到上限...阻塞处理");
lock.wait();// 进行阻塞处理
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Car car = CarFactory.makeNewCar();
carList.add(car);// 加到仓库中去
carNums++;// 总数增加1
lock.notify();// 唤醒等待的线程 System.out.println("生产汽车-->count = " + carNums);
return carNums;
}
} public int get() {// 提供给消费者从这边取汽车接口
Car car = null;
synchronized (lock) {
if (carList.size() == 0) {// 没有汽车可以用来消费
try {
System.out.println("没有汽车...阻塞处理");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (carList.size() != 0) {// size不为空才去取车
car = carList.get(carList.size() - 1);// 提取最后一个car
carList.remove(car);// 从车库list中移除掉
carNums--;// 总数减少1
}
lock.notify();
System.out.println("消费汽车-->count = " + carNums);
return carNums;
}
} public static class Car { public String carName;// 汽车名称
public double carPrice;// 汽车价格 public Car() {
} public Car(String carName, double carPrice) {
this.carName = carName;
this.carPrice = carPrice;
}
}
} /**
* 采用静态工厂方式创建car对象,这个只是简单模拟,不做设计模式上的过多考究
*/
public static class CarFactory { private CarFactory() {
} public static Car makeNewCar(String carName, double carPrice) {
return new Car(carName, carPrice);
} public static Car makeNewCar() {
return new Car();
}
} /**
* 第二个版本的生产者和消费者线程,加上了同步机制的方法
*
* @param args
*/
public static void main(String[] args) {
CarBigHouse bigHouse = new CarBigHouse();
new Thread(new CarSeller(bigHouse)).start();
new Thread(new Consumer(bigHouse)).start();
} }

结果展示:

生产汽车-->count = 1
生产汽车-->count = 2
生产汽车-->count = 3
生产达到上限...阻塞处理
消费汽车-->count = 2
消费汽车-->count = 1
消费汽车-->count = 0
没有汽车...阻塞处理
生产汽车-->count = 1
生产汽车-->count = 2
生产汽车-->count = 3
生产达到上限...阻塞处理
消费汽车-->count = 2
消费汽车-->count = 1
消费汽车-->count = 0
没有汽车...阻塞处理
生产汽车-->count = 1
生产汽车-->count = 2
生产汽车-->count = 3
生产达到上限...阻塞处理
消费汽车-->count = 2
消费汽车-->count = 1
消费汽车-->count = 0
没有汽车...阻塞处理
生产汽车-->count = 1
消费汽车-->count = 0

到此,简单的demo测试结束。

注:本文测试代码参考于 吖梁 http://blog.csdn.net/u012954390/article/details/51301873,我只是稍作了修改。

java多线程的简单demo的更多相关文章

  1. Java 多线程异步处理demo

    java中实现多线程 1)继承Thread,重写里面的run方法 2)实现runnable接口通过源码发现:第一种方法说是继承Tread然后重写run方法,通过查看run方法的源码,发现run方法里面 ...

  2. Java 多线程安全问题简单切入详细解析

    线程安全 假如Java程序中有多个线程在同时运行,而这些线程可能会同时运行一部分的代码.如果说该Java程序每次运行的结果和单线程的运行结果是一样的,并且其他的变量值也都是和预期的结果是一样的,那么就 ...

  3. Java多线程——<三>简单的线程执行:Executor

    一.概述 按照<Java多线程——<一><二>>中所讲,我们要使用线程,目前都是显示的声明Thread,并调用其start()方法.多线程并行,明显我们需要声明多个 ...

  4. WinForm多线程编程简单Demo

    需要搭建一个可以监控报告生成的CS(WinForm)工具,即CS不断Run,执行获取数据生成报告,经过研究和实践,选择了使用"WinForm多线程编程"的解决方案.当然参考了园中相 ...

  5. Java多线程实现简单的售票程序

    设计一个多线程程序如下:设计一个火车售票模拟程序.假如火车站要有100张火车票要卖出,现在有5个售票点同时售票,用5个线程模拟这5个售票点的售票情况 1.要求打印出每个售票点所卖出的票号 2.各售票点 ...

  6. java多线程并发执行demo,主线程阻塞

    其中有四个知识点我单独罗列了出来,属于多线程编程中需要知道的知识: 知识点1:X,T为泛型,为什么要用泛型,泛型和Object的区别请看:https://www.cnblogs.com/xiaoxio ...

  7. java 多线程断点下载demo

    源码链接 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java ...

  8. Java多线程之简单的线程同步实例

    数据类: package Thread.MyCommon; public class Data { public int num = 0; public synchronized int getEve ...

  9. JAVA多线程实现简单的点名系统

    效果图如下: CMain函数: package com.shubing.main; public class CMain { public static void main(String[] args ...

随机推荐

  1. Inside Amazon's Kafkaesque "Performance Improvement Plans"

    Amazon CEO and brilliant prick Jeff Bezos seems to have lost his magic touch lately. Investors, empl ...

  2. matlab操作(整理)

    http://blog.csdn.net/ysuncn/article/details/1741828 http://zhan.renren.com/h5/entry/3602888498000464 ...

  3. Springboot+RestTemplate 简单使用

        spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值 ...

  4. November 22nd 2016 Week 48th Tuesday

    Eventually, you will learn to cry on the inside. 终有一天,你得学会让眼泪在心里流. Cry on the inside. I am tired, an ...

  5. HTML5 JS 实现浏览器全屏(F11的效果)

    项目中有需要使用JS来控制浏览器全屏的方法 DEMO地址: http://zhongxia245.github.io/demo/js2fullpanel.html function fullScree ...

  6. 第二章 Google guava cache源码解析1--构建缓存器

    1.guava cache 当下最常用最简单的本地缓存 线程安全的本地缓存 类似于ConcurrentHashMap(或者说成就是一个ConcurrentHashMap,只是在其上多添加了一些功能) ...

  7. numpy的array数据类型(创建)

    import numpy as np # 创建 # 创建一维数组 a = np.array([1, 2, 3]) print(a) ''' [1 2 3] ''' # 创建多维数组 b = np.ar ...

  8. 搭建高可用mysql系列(2)-- Percona XtraDB Cluster 安装

    本文主要介绍在 centos 下 Percona XtraDB Cluster(下文简称PXC) 的安装, 个人的系统版本信息如下: [root@c2-d09 worker]# more /etc/r ...

  9. Python中乘法

    1.numpy乘法运算中"*"或multiply(),是数组元素逐个计算,具体代码如下: import numpy as np # 2-D array: 2 x 3 two_dim ...

  10. 控制层方法中获取url目录

    控制层方法中获取url目录 Request.Url.GetLeftPart(UriPartial.Authority).ToString(); //返回 http://localhost:9246(网 ...