一、synchronized简介
synchronized 是 Java 中的关键字,是一种同步锁。它修饰的对象有以下几种:
1、修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{} 括起来的代码,作用的对象是调用这个代码块的对象;
2、修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3、修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象; 4、修改一个类,其作用的范围是 synchronized 后面括号括起来的部分,作用主的对象是这个类的所有对象。
注意:虽然可以使用 synchronized 来定义方法,但 synchronized 并不属于方法定义的一部分,因此,synchronized 关键字不能被继承。如果在父类中的某个方法使用了 synchronized 关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized 关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。
二、synchronized的简单使用:多人售票案例
本例实现3个人卖30张票
/** * synchronized练习,3个人卖30张票 */ //第一步:创建资源类,定义属性和操作方法 class Ticket{ //票的数量 private int number = 30; //卖票方法 public synchronized void sale(){ if (number > 0){ System.out.println(Thread.currentThread().getName() + "卖出票,还剩" + --number + "张票"); } } } public class SaleTicket { //第二步,创建多个线程,调用资源类中的操作方法 public static void main(String[] args) { Ticket ticket = new Ticket(); //线程1 new Thread(new Runnable() { @Override public void run() { for(int i=0; i<40; i++){ //卖票 ticket.sale(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "售票员A").start(); //线程2 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 40; i++) { //卖票 ticket.sale(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "售票员B").start(); //线程3 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 40; i++) { //卖票 ticket.sale(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "售票员C").start(); } }
运行结果:
售票员A卖出票,还剩29张票 售票员B卖出票,还剩28张票 售票员C卖出票,还剩27张票 售票员B卖出票,还剩26张票 售票员C卖出票,还剩25张票 售票员A卖出票,还剩24张票 售票员C卖出票,还剩23张票 售票员B卖出票,还剩22张票 售票员A卖出票,还剩21张票 售票员C卖出票,还剩20张票 售票员B卖出票,还剩19张票 售票员A卖出票,还剩18张票 售票员C卖出票,还剩17张票 售票员B卖出票,还剩16张票 售票员A卖出票,还剩15张票 售票员C卖出票,还剩14张票 售票员B卖出票,还剩13张票 售票员A卖出票,还剩12张票 售票员C卖出票,还剩11张票 售票员B卖出票,还剩10张票 售票员A卖出票,还剩9张票 售票员C卖出票,还剩8张票 售票员B卖出票,还剩7张票 售票员A卖出票,还剩6张票 售票员C卖出票,还剩5张票 售票员A卖出票,还剩4张票 售票员B卖出票,还剩3张票 售票员C卖出票,还剩2张票 售票员B卖出票,还剩1张票 售票员A卖出票,还剩0张票