Java基础学习之线程

一、“监视线程”通讯模型

概念:同时多个独立线程在运行,运行状态由第三方监控线程全程监控,这种模型为监视线程模型

如下所示:

二、线程同步问题

多线程程序可能存在的一个问题就是:可能会出现多个线程同时操作某一个对象的数据,结果就会出现线程对象对自己操作的数据不同步的情况。

如图:



例子:

package com.test.thread;

/**
 * 账户类
 * 
 * @author lhz
 * 
 */
public class Account {
	private int count;

	public Account(int count) {
		this.count = count;
	}

	/**
	 * 取现的方法
	 */
	public int getCount(int cash) {
		// synchronized (this) {
		if (count < cash) {
			System.out.println("你的余额不足,余额为" + count + "取现失败");
			return -1;
		}
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		count = count - cash;
		// }

		return count;

	}
}
package com.test.thread;

/**
 * 客户线程类
 * 
 * @author lhz
 * 
 */
public class Costomer extends Thread {
	private Account account;
	private int cash;
	private String type;

	public Costomer(Account account, int cash, String type) {
		this.cash = cash;
		this.account = account;
		this.type = type;
	}

	/**
	 * 取现
	 */
	public void run() {
		int result = account.getCount(cash);
		if (result < 0) {
			System.out.println(type + "取现失败,您余额不足");
		} else {
			System.out.println(type + "取现成功,您取了" + cash + ",余额还有" + result);
		}
	}
}
package com.test.thread;

public class ThreadTest {
	public static void main(String[] args) {
		Account account = new Account(5000);
		Costomer c1 = new Costomer(account, 4000, "atm");
		Costomer c2 = new Costomer(account, 3000, "柜台");
		c1.start();
		c2.start();
	}
}
会出现这里两种情况





第一张图:这个是因为,程序先执行c2.start(),调用getCount(int cash)方法,执行到休眠;c1.start()执行,执行到休眠;c2又执行,执行

count = count - cash;
此时count=2000;但是c1的count还是5000,然后c1执行
count = count - cash;
此时count=1000,最终 count=1000.
第二张图:这个是因为,程序先执行c1.start(),调用getCount(int cash)方法,执行到休眠;c2.start()执行,执行到休眠;c1又执行,执行

count = count - cash;
此时count=1000;但是c1的count还是5000,然后c1执行

count = count - cash;
此时count=2000,最终 count=2000.

不管是那种情况,对于银行来说都是亏本的,如何解决这个问题呢?

三、synchronized:同步锁关键字,锁定当前对象或者方法,一家独用

简介:

1、synchronized代码块中的语句只能有一个线程在执行      

2、任意一个对象都有一个标志位,有1和0两种状态
3、当程序执行到synchronized代码块的时候线程会检查对象的标志位是1还是0

4、如果是1则执行程序,同是将对象的标志位设置为0,其他线程执行到synchronized代码块时一看对象标志位为0 则线程会阻塞,一直等到对象的标志位为1再执行下面的程序 

实例(还是上面的例子):锁定同一个对象

synchronized (this) {
			if (count < cash) {
				System.out.println("你的余额不足,余额为" + count + "取现失败");
				return -1;
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			count = count - cash;
		}
四、 wait/notify机制
       在java中,每个对象都有从Object父类继承而来的两个关于线程间通讯的方法wait()和notify(),如其方法名所示,一个是等待,一个是通知,当在一个对象上调用wait()方法时,当前线程就会进行wait状态,直到收到另一个对象的notify()发出通知,才会执行下一步计算

        在多线程通讯中,经常会用对象的这两个方法,一个典型的案例就是“生产/消费者模型”

五、生产/消费者模型

模型规则
        生产和消费线程共同操作一个集合,生产线程放入对象,消费线程取出对象!仅当集合中没有对象时,生产线程会放入一个对象,如有集合中有一个对象时,消费线程要马上取出这个对象。

如图所示 :


实例:

package com.test.thread1;

/**
 * 手机类
 * 
 * @author lhz
 * 
 */
public class Phone {
	public int type;
}

package com.test.thread1;

import java.util.ArrayList;

/**
 * 消费者
 * 
 * @author lhz
 * 
 */
public class Costomer extends Thread {
	private Phone phone;
	private ArrayList<Phone> list;

	public Costomer(Phone phone, ArrayList<Phone> list) {
		this.phone = phone;
		this.list = list;
	}

	public void run() {
		while (true) {
			// synchronized (list) {
			if (list.size() >= 1) {
				list.remove(0);// 取出
				// list.notify();
				System.out.println("消费了" + phone.type);

				phone.type++;
			} else {
				continue;
				// try {
				// list.wait();// 等待
				// } catch (InterruptedException e) {
				// e.printStackTrace();
				// }
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// }
		}
	}
}
package com.test.thread1;

import java.util.ArrayList;

/**
 * 生产者
 * 
 * @author lhz
 * 
 */
public class Product extends Thread {
	private Phone phone;
	private ArrayList<Phone> list;

	public Product(Phone phone, ArrayList<Phone> list) {
		this.phone = phone;
		this.list = list;
	}

	public void run() {
		while (true) {
			// synchronized (list) {
			if (list.size() <= 0) {
				list.add(phone);// 放入
				// list.notify();// 通知
				System.out.println("生产出" + phone.type);
				phone.type++;
			} else {
				continue;
				// try {
				// list.wait();// 等待
				// } catch (InterruptedException e) {
				// e.printStackTrace();
				// }
			}

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// }
		}
	}
}
package com.test.thread1;

import java.util.ArrayList;

public class TestThread {
	public static void main(String[] args) {
		Phone phone = new Phone();
		ArrayList<Phone> list = new ArrayList<Phone>();
		Product p = new Product(phone, list);
		Costomer c = new Costomer(phone, list);
		p.start();
		c.start();
	}
}
cpu消耗非常大,效率低



使用了wait/notify,但是没有使用同步锁

while (true) {
			// synchronized (list) {
			if (list.size() >= 1) {
				list.remove(0);// 取出
				list.notify();
				System.out.println("消费了" + phone.type);

				phone.type++;
			} else {

				try {
					list.wait();// 等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// }
		}
	
while (true) {
			// synchronized (list) {
			if (list.size() <= 0) {
				list.add(phone);// 放入
				list.notify();// 通知
				System.out.println("生产出" + phone.type);
				phone.type++;
			} else {

				try {
					list.wait();// 等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// }
		}



加了同步锁

while (true) {
			synchronized (list) {
				if (list.size() <= 0) {
					list.add(phone);// 放入
					list.notify();// 通知
					System.out.println("生产出" + phone.type);
					phone.type++;
				} else {

					try {
						list.wait();// 等待
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
while (true) {
			synchronized (list) {
				if (list.size() >= 1) {
					list.remove(0);// 取出
					list.notify();
					System.out.println("消费了" + phone.type);

					phone.type++;
				} else {

					try {
						list.wait();// 等待
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
cpu占内存少了,不会出现做无用功情况




注意:

  1)wait和notify必须在同步锁之内使用
  2)同步锁锁定对象和wait、notify对象必须同一个
  3)当对象wait挂起状态时候是会释放同步锁的

六、线程生命周期


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值