1、临界资源问题
—————临界资源:多个线程共享的数据。
public class Stack {
int idx=0;
char[] data=new char[10];
public void push(char c) {
synchronized (this) { 在执行该代码段时必须取得对象锁
data[idx]=c;
idx++;
}
}
public synchronized char pop() { 在执行该方法时必须取得对象锁
idx--;
return data[idx];
}
}
如何解决多线程安全问题
-
怎么实现
把多条语句操作共享的代码锁起来,任意时刻只执行一个线程
-
同步代码块
synchronized 的作用
给调用方法的对象加锁,保证一个方法处理的对象资源不会因其他方法的执行而改变。
- 使用方法:
- 用在对象前面限制一段代码的执行;
- 在方法前,表示该方法为同步方法。
- 格式:
synchronized (任意对象){
多条语句操作共享数据的代码
}
执行同步代码的过程
问题描述:
SellTick类:
1、定义类实现Runnable接口
2、覆盖Runnable接口的run方法。将线程要运行的代码存放在该run方法中。
SellTicketDemo类
3、通过Thread类建立线程对象。
4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runnable接口的子类对象传递给Thread的构造函数。
因为,自定义的run方法所属的对象的是Runnable 的接口的子类对象。所以要让线程去执行指定对象的run方法。就必须明确该run方法所属的对象。
5、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
//class SellTick implements Runnable{ 由于线程执行的随机性会出现票的序号重复和出现负数现象
// private static int tickets=100;
// public void run(){
// while(true){
// if(tickets>0)
// {
// System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
// tickets--;
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// }
// }
//
// }
//}
class SellTick implements Runnable{
private static int tickets=100;
private Object obj=new Object();
public void run(){
synchronized (obj){ //三个线程使用同一把锁,不能使用synchronized (new Objct()),
while(true){
if(tickets>0)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
SellTick se=new SellTick();
Thread t1=new Thread(se,"窗口1");
Thread t2=new Thread(se,"窗口2");
Thread t3=new Thread(se,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
2 wait()和notify() 方法
wait( ):释放对象锁,进入等待阻塞状态
notify( ):通知等待者执行(随机选择)
- 这两个方法配套使用
- 使用要求:
- 必须在 synchronized 方法或块中调用。因为只有在同步代码段中才存在资源锁定。
- 这对方法直接隶属于Object 类,而不是Thread类。
采用wait和notify可以解决很多临界访问控制问题 ```java class Bridge { private boolean engaged = false; //桥的占用状态
public synchronized void getBridge( ) { //取得上桥资格
while (engaged ) {
try {
wait( ); //如果桥被占用就循环等待
} catch ( InterruptedException exception ) { }
}
engaged = true; //占用桥
}
public synchronized void goDownBridge( ) {//下桥
engaged = false;
notifyAll( ); //唤醒其他等待线程
} }
class PersonPassBridge extends Thread { private Bridge bridge; //桥对象 String id; //人的标识 public PersonPassBridge (String id, Bridge b ) { bridge = b; this.id=id; } public void run( ) { bridge.getBridge(); //等待过桥 System.out.println(id +”正过桥…”); try { Thread.sleep((int)(Math.random()* 1000)); } catch( InterruptedException exception ) { } bridge.goDownBridge( ); //下桥 } }
public class Test{ public static void main( String args[ ] ) { Bridge b =new Bridge( ); PersonPassBridge x; for (int k=1;k<=4;k++) { x = new PersonPassBridge(“南边,第”+k+”人”, b); x.start( ); } for (int k=1;k<=3;k++) { x = new PersonPassBridge(“北边,第”+k+”人”, b); x.start( ); } } } 南边,第1人正过桥… 南边,第2人正过桥… 北边,第3人正过桥… 南边,第3人正过桥… 北边,第2人正过桥… 南边,第4人正过桥… 北边,第1人正过桥… ```