(1)问题:卖票的过程出现重票和错票
(2)缘由:当某个线程操做车票的过程当中,还没有操做完成,其余线程参与进来,也操做车票
(3)解决:当一个线程a在操做共享对象时,其余线程不能参与进来,直到线程a操做完毕,其余
线程才能够开始操做共享对象。
这种状况,即便线程a出现了阻塞,也不能被改变
(4)java中经过同步机制,来解决线程的安全问题:java
synchronized(同步监视器){ //须要被同步的代码(操做共享数据的代码) //共享数据:多个线程共同操做的变量 //不能包含太多,不也能包太少 }
同步监视器----俗称:锁,任何一个类的对象,均可以充当锁
要求:多个线程必需要共用同一把锁,惟一性
补充1:在实现Runnable接口中,使用this作同步监视器 安全
class Window1 implements Runnable { /*只创造了一个Window1对象,所以能够实现100张票共享*/ private int ticket=100; Object ob=new Object();//任何一个类的对象,均可以充当锁 @Override public void run() { while(true){ synchronized(this) {//此时的this:惟一的window1对象,不用在另外建立一个类的对象 // synchronized(ob) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "卖票:" + ticket); ticket--; } else { break; } } } } }
补充2:在继承Thread类建立多线程的方式中,使用 线程类.class 做为同步监视器,慎用this多线程
class Window2 extends Thread{ private static int ticket=100; private static Object obj=new Object(); @Override public void run(){ while(true) { // synchronized (obj) { synchronized (Window2.class) {//类类型的对象也能够 // synchronized(this) {错误,在继承这种方法的时候不能写this,由于new的时候会产生多个对象 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if (ticket > 0) { System.out.println(getName() + "卖票:" + ticket); ticket--; } } } } } }
将须要进行同步的代码放在一个方法中,给方法加上synchronized
关于同步方法的总结:
①同步方法仍然涉及到同步监视器,只是不须要显示声明
②非静态的同步方法:同步监视器是:this
静态的同步方法:同步监视器是当前类的自己 类.classide
1.用同步方法解决,实现Runnable接口建立多线程 this
class Window3 implements Runnable { /*只创造了一个Window1对象,所以能够实现100张票共享*/ private int ticket=100; @Override public void run() { while(true){ show(); } } private synchronized void show(){ if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖票:" + ticket); ticket--; } } }
2.同步方法解决继承Thread类建立多线程 线程
class Window4 extends Thread{ private static int ticket=100; @Override public void run(){ while(true) { show(); } } private static synchronized void show(){//此时同步监视器:Window4.class //private synchronized void show(){//同步监视器的对象不惟一,和new 有关 if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖票:" + ticket); ticket--; } } }
好处----同步的方式,解决了线程的安全问题
局限性----操做同步代码时,只能有一个线程参与,其余线程等待。至关因而一个单线程的过程,效率低code