一、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张票