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人正过桥… ```
