1.什么是线程安全:
java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如对同一个数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。
二、 如何使用同步?
在网上简单的搜了一下,发现同步的方式有5-7种,其实同步来同步去,里面的原理是没有变化的,那么今天就简单来讲一种:
1、用 synchronized 关键字修饰方法、代码块
实现线程安全:synchronized
(1)方法加锁
public synchronized void a(){
//在该方法中可以访问共享的对象
}
(2)代码块加锁
public void b(){
synchronized(共享对象){
i++;
}
}
注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。
三、如上所说,我们就接着上一篇的卖票系统来增加多个窗口卖票,也就是增加多个线程,来演示一下线程的同步:
(一)演示背景:假设我们有一个卖票系统,共有50张票,原来只有一个窗口,现在因为近期生意火爆,顾客排队等待时间较长,所以现在要增加三个窗口,那么写到代码中就是增加三个线程(一个窗口代表卖票的一个线程,那选在就一共有四个线程)
(二)代码的类与方法与上一篇的一样,不一样的就是在测试阶段,增加了三个线程,代码如下:
2)票的类
/**
*@ClassName Tickets
*@Description TODD
*@AUTHOR sh-wangbs
*@Date 2019/2/279:55
*@Version 1.0
**/
//该注解省去了 get set 方法
@Data
public class Tickets {
//票的总数
private int count;
//有参构造
public Tickets(int count) {
super();
this.count = count;
}
//无参构造
public Tickets() {
super();
}
}
2)实现Runnable接口的卖票的类
**
*@ClassName SaleTicketsbyRannable
*@Description TODD
*@AUTHOR sh-wangbs
*@Date 2019/2/279:55
*@Version 1.0
**/
@Data
public class SaleTicketsbyRannable implements Runnable {
//获得票的类
public Tickets tic;
//有参构造
public SaleTicketsbyRannable(Tickets tic) {
super();
this.tic = tic;
}
@Override
public void run() {
while (tic.getCount()>0){
sale();
}
}
//卖票的方法(这里的synchronized 关键字起这关键的作用,就是给该方法加锁)
public synchronized void sale() {
//获取当前线程的名字,直观的看出是哪个线程
String threadname = Thread.currentThread().getName();
//如果票数大于零卖票
if(tic.getCount()>0){
System.out.println(threadname+":第"+tic.getCount()+"张票已售出!");
//卖票后总票数减1
tic.setCount(tic.getCount()-1);
try {
//线程沉睡0.2秒,只是方便看演示效果
Thread.currentThread().sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
//当票数为0是输出“票已售空"
tic.setCount(tic.getCount());
System.out.println(threadname+"的票已售空!");
}
}
}
3)演示五个窗口卖票结果的测试类
/***
* @Description: 卖票测试类
* @Param:
* @return:
* @author: wangbs
* @create: 2019/2/27 11:06
*/
public class TestSaleTickets {
public static void main(String[] args) {
//票的实体类,有100张票
Tickets tic = new Tickets(100);
//创建一个多线程
SaleTicketsbyRannable str = new SaleTicketsbyRannable(tic);
//开启五个线程也就是五个卖票窗口
Thread thread1 = new Thread(str,"卖票窗口1");
Thread thread2 = new Thread(str,"卖票窗口2");
Thread thread3 = new Thread(str,"卖票窗口3");
Thread thread4 = new Thread(str,"卖票窗口4");
Thread thread5 = new Thread(str,"卖票窗口5");
//执行
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
4)演示效果
由结果可知,五个卖票的窗口,同时开始售票,但是在内部机制里还是一个一个的 来执行的,里面的执行是无序的,买次售票都需要对应的线程抢占资源,才能卖票,也就是说,哪个线程先获得资源,哪个线程就先执行,到售完票以后,若再次访问窗口,则会提示“票已售完”的信息!这就是线程之间的同步!
(下一篇我会讲下线程间的通信问题)