Java多线程系列-------同步函数和同步代码块
上次我们在卖票问题中,抛出了一个问题。当我们的四个窗口也就是四个线程同时开始售票时,就会出现对于共享资源的抢夺问题。关于共享资源的抢夺因为代码不是原子性出现了数值上的差错。那么怎么样来解决这个问题呢。现在我来讲解一下java中的一个关键字synchronized。
首先来解释一个这个关键字的含义,synchronized意思是同步。换句话说,关于synchronized修饰的代码范围,不同的线程在这个区域的代码执行是有先后顺序的。如果我们给共享资源的作用代码范围内加上synchronized进行修饰,那么我们就可以让不同的线程在操作我们的共享资源时有先后顺序。这样就保证了代码的正确性。
在实现具体的代码之前,我们需要知道怎么来使用我们的synchronized关键字。我们需要明确一个概念,synchronized是一种锁机制。换句话说,我们需要为一个对象或者一个类标明一个锁,当线程想要执行相应的synchronized修饰的代码块时,它需要获得synchronized修饰的对象或者类的锁,这个就是cpu的使用权。只有拿到了锁才可以被cpu调度,获得处理权。当synchronized代码块执行结束后,这个线程就要释放相应的锁。cpu可以把这个锁分给其他的线程。
关于同步锁,实际上可以分为两种,一种是同步函数,一种是同步代码块。
先来看同步函数。
public synchronized void method() {}
那么我们知道synchronized需要对一个对象或者类加锁,那么这个同步函数加的锁是什么呢。这个地方很显然是对this对象,也就是当前对象加了锁。这是一个类方法,类方法是和对象对应的。只有在我们实例化一个对象的时候才会为我们方法分配相应的内存空间。所以如果为类方法加了一个锁,那么这个锁对应的就是this。
public static synchronized void sale() {}
我们再来看这个,静态方法,那么synchronized对应的锁是什么呢。没错就是和类对应的,这个类的class文件。
说完了同步函数,同步代码块就很简单了。它的锁的对象是要我们自己决定的
synchronized (obj) {
}
那么我们的同步函数和同步代码块可以互换吗,当然是可以的。他们的互换机制如下,具体的理由我就不再阐述。
public void synchronized method{}
synchronized(this){
}
public static void synchronized method(){}
synchronized(Class.class){
}
那么重回我们最初的问题,我相信你一定知道了怎么去解决这个问题了。那就是在票的数目的操作上加上synchronized关键字修饰即可。
package com.zzu.my.thread.test.thread;
class SellTicket extends Thread{
private static int tickets = 20;//初始化有20张票
//买票这个动作被多个窗口执行也就是被多个线程执行,要将这些代码中定义到线程任务中
//run方法中
@Override
public void run(){
while(true){
if(tickets>0){
System.out.println("窗口: "+Thread.currentThread().getName()+"出售了第"+tickets--+"张票");
}else{
break;
}
}
}
}
/**
* 模拟售票窗口
* @author Administrator
*
*/
public class TicketDemo {
public static void main(String[] args) {
SellTicket t1 = new SellTicket();
SellTicket t2 = new SellTicket();
SellTicket t3 = new SellTicket();
SellTicket t4 = new SellTicket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
有一点我们需要注意,当我们想要让多个线程对同一个资源处理的时候,我们需要使用的同一把锁,也就是synchronized修饰的对象是同一个即可。否则就会出现不同的锁,会出现两个线程同时对一个资源进行读取,会出现数字上的差错。
还没有评论,来说两句吧...