------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
实例讲解
/*
* 需求:某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有100张票,
* 而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
* 用实现Runnable接口的方式完成。
出现问题:
1.卖出了相同编号的票
因为cpu的操作是原子性的
先记录以前的值
接着把ticket--
然后输出以前的值(t2来了)
ticket的值就变成了99
窗口1正在出售第100张票
窗口2正在出售第100张票
2.出现了负数票
随机性和延迟导致的
判断线程安全问题产生的根本原因:
A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
解决问题:
把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。
同步机制
*/
A:通过同步机制解决线程安全问题
/*
* 同步机制解决线程安全问题
* 同步代码块:
* synchronized(对象){
* 需要同步的代码;
* }
* 对象可以是任意的
*
*/
public class SellTicket implements Runnable {
// 因为是3个窗口共享,所以用静态修饰,被多个线程共享
private static int ticket = 100;
// 创建锁对象
private Object obj = new Object();
// 重写run方法
@Override
public void run() {
// 只要还有票就一直卖,直到卖完为止
synchronized (obj) {<span style="white-space:pre"> </span>//同步代码块
while (ticket > 0) {
// 为了更真实,让卖票间隔100毫秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖出第"
+ (ticket--) + "张票。");
}
}
}
}
B:通过创建锁对象来解决线程安全问题
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* 使用锁对象实现线程安全
*/
public class SellTicket2 implements Runnable {
private int ticket = 100;
// 创建锁对象
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
/*
* //加锁 lock.lock(); if(ticket>0){ try { Thread.sleep(100); } catch
* (InterruptedException e) { // TODO Auto-generated catch block
* e.printStackTrace(); }
* System.out.println(Thread.currentThread().getName
* ()+"正在出售第"+(ticket--)+"张票。"); } //解锁 lock.unlock();
*/
// 为了保证锁一定会被释放,可以使用try....finally..结构
// 加锁
try {
lock.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (ticket--) + "张票。");
}
} finally {
// 释放锁
lock.unlock();
}
}
}
}
测试代码
public class SellTicketDemo {
public static void main(String[] args) {
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
关于同步机制中锁对象的说明:
A:同步代码块的锁对象可以是任意的。
B:同步方法的的锁对象是:this
C:静态同步方法的锁对象是:this.getClass()当前类的字节码文件对象