synchronized是Java并发编程中的同步机制关键字,它能保证同一个时刻只有一条线程能够执行被关键字修饰的代码,其他线程就会在队列中进行等待,等待这条线程执行完毕后,下一条线程才能对执行这段代码。
synchronized的应用:
1.修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
2.修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
3.修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁
假如我们有一个简单的卖票系统如下:
public class Thread
{
public static void main(String [] args)
{
Tickets tickets=new Tickets(100);
Operate operate=new Operate(tickets);
new Thread(()->{
while(tickets.getNum()>0) operate.sale();
},"窗口1").start();
new Thread(()->{
while(tickets.getNum()>0) operate.sale();
},"窗口2").start();
new Thread(()->{
while(tickets.getNum()>0) operate.sale();
},"窗口3").start();
new Thread(()->{
while(tickets.getNum()>0) operate.sale();
},"窗口4").start();
}
}
public class Tickets {
private int num;
public Tickets(){};
public Tickets(int num){
this.num=num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
public class Operate {
private Tickets tickets;
public Operate(Tickets tickets){
this.tickets=tickets;
}
public void sale(){
if(tickets.getNum()>0){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(tickets.getNum()>0){
int num=tickets.getNum();
System.out.println(Thread.currentThread().getName()+"正在
卖票:"+tickets.getNum()+"售票剩余"+num);
--num;
tickets.setNum(num);
}
}
}
}
synchronized作用于实列方法
当synchronized关键字修饰实例方法时,它会获取当前实例对象的锁,并对整个方法体进行同步控制。只有获取到锁的线程才能执行该方法,其他线程需要等待锁释放。
在上述卖票系统的例子中,如果将synchronized关键字应用于实例方法sale(),则代码如下:
public synchronized void sale() {
// 。。。。。。
}
在这种情况下,每个窗口线程在调用sale()
方法时,都会尝试获取当前Tickets实例对象的锁。只有一个线程能够获取锁,执行售票逻辑,其他线程需要等待锁释放。这样可以确保每次只有一个线程执行售票操作,避免并发问题。
synchronized作用于静态方法
当synchronized关键字修饰静态方法时,它会获取该方法所属类的Class对象的锁,并对整个静态方法进行同步控制。只有获取到锁的线程才能执行该静态方法,其他线程需要等待锁释放。
在上述卖票系统的例子中,如果将synchronized关键字应用于静态方法sale()
,则代码如下:
public static synchronized void sale() {
// 。。。。。。
}
在这种情况下,无论创建了多少个Tickets实例对象,所有窗口线程在调用sale()
方法时,都会尝试获取Tickets.class对象的锁。只有一个线程能够获取锁,执行售票逻辑,其他线程需要等待锁释放。这样可以确保每次只有一个线程执行售票操作,避免并发问题。
synchronized作用于代码块
synchronized关键字还可以应用于代码块级别,即修饰一段代码块。在这种情况下,它会获取指定对象的锁,并对代码块进行同步控制。只有获取到锁的线程才能执行该代码块,其他线程需要等待锁释放。
在上述卖票系统的例子中,如果将synchronized关键字应用于代码块,代码如下:
public void sellTicket() {
// ......
synchronized (this) {
//......
}
}
在这种情况下,通过synchronized关键字修饰的代码块,使用this作为锁对象。当一个线程进入同步代码块时,它会获取当前实例对象的锁。其他线程如果也想执行该代码块,则需要等待锁释放。
synchronized的包含三个特性:
1.原子性:使用synchronized实现了同步,同步实现了原子性,保证了被同步的代码块在同一时间只有一个线程在执行。
2.可见性:当一个线程修改了共享变量的值时,其他线程能够立即得知这个修改。
3.有序性:禁止代码重排序