/**
?*
购票案例
多线程同步
多线程的并发执行虽然可以提高程序的效率,但是,当多个线程去访问同一个资源时,也会引发一些安全问题。
并发:同一个对象被多个线程同时操作。
处理多线程问题时,多个线程访问同一个对象﹐并且某些线程还想修改这个对象﹒这时候我们就需要线程同步.
线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用
由于同一进程的多个线程共享同一块存储空间﹐在带来方便的同时,也带来了访问冲突问题﹐为了保证数据在方法中被访问时的正确性,
在访问时加入锁机制synchronized,当一个线程获得对象的排它锁,独占资源﹐其他线程必须等待,使用后释放锁即可.
存在以下问题:
一个线程持有锁会导致其他所有需要此锁的线程挂起;
在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题.
我们可以通过private关键字来保证数据对象只能被方法访问﹐所以我们只需要针对方法提出一套机制,
这套机制就是synchronized关键字,目前多线程同步有常用的两种方法,分别是同步代码块和同步方法。
同步代码块
当多个线程使用同一个资源时,可以将处理共享资源的代码放置在一个代码块中,使用synchronized关键字来修饰,被称作同步代码块
上述代码中,lock是一个锁对象称之为同步监视器,它是同步代码块的关键。当线程执行同步代码块时,首先会检查锁对象的标志位,
默认情况下标志位为1,此时线程会执行同步代码块,同时将锁对象的标志位置为0。
当一个新的线程执行到这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,
新线程才能进人同步代码块执行其中的代码。循环往复,直到共享资源被处理完为止。
同步方法
在方法前面同样可以使用synchronized关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能。具体语法格式如下:
synchronized方法控制对“对象”的访问,被synchronized修饰的方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞,
直到当前线程访问完毕后,其他线程才有机会执行方法。
缺陷:若将一个大的方法申明为synchronized将会影响效率。
?*/
public class MySite implements Runnable{
????public static void main(String[] args) {
????????MySite site = new MySite();
Thread t1 = new Thread(site,"林枫");
Thread t2= new Thread(site,"叶凡");
Thread t3 = new Thread(site,"石昊");
????????t1.start();
????????t2.start();
????????t3.start();
????}
//定义票的数量
????int count = 10;
//定义购买了第几张票
????int sum = 0;
????@Override
????public void run() {
????????while (true){
????????????synchronized (this){
????????????????if (count==0)
????????????????????break;
????????????????count--;
????????????????sum++;
????????????????try {
????????????????????Thread.sleep(100);
????????????????} catch (InterruptedException e) {
????????????????????e.printStackTrace();
????????????????}
System.out.println(Thread.currentThread().getName()+"购买了第"+sum+"张票,剩余"+count+"张票");
????????????}
????????}
????}
}