同步块性能优化的代码
/*
* 线程安全:在并发时保证数据的正确性,同时保证效率尽可能高
* synchronized
* 1.同步方法(在方法上面加synchronized)
* 2.同步块
*/
public class SynBlockTest03 {
public static void main(String[] args) {
//一份资源
SynWeb12306 web=new SynWeb12306();
//多个代理
new Thread(web,"laoda").start();
new Thread(web,"laoer").start();
new Thread(web,"laosan").start();
}
}
class SynWeb12306 implements Runnable{
//票数
private int ticketNums=3;
private boolean flag=true;
@Override
public void run() {
while(flag) {
test5();
}
}
//线程安全:尽可能锁定合理的范围(不是指的代码而是数据的完整性)
//在多线程里面称为双重检测(主要考虑的就是临界值的问题)
public void test5() {
//假设还有一张票,多个线程进来,这一块的代码拦不住
if(ticketNums<=0) {//考虑的是没有票的情况
flag=false;
return;
}
synchronized (this) {
if(ticketNums<0) {//考虑的是最后一张票
flag=false;
return;
}
//模拟网络延时
try {
Thread.sleep(200);
//进入了阻塞状态,然后200s以后我就重新等待CPU的调用
//继续执行下面的代码
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}
//线程不安全 范围太小锁不住
public void test4() {
synchronized (this) {
if(ticketNums<0) {
flag=false;
return;
}
}
//模拟网络延时
try {
Thread.sleep(200);
//进入了阻塞状态,然后200s以后我就重新等待CPU的调用
//继续执行下面的代码
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
//线程不安全锁定失败 ticketNums对象在变(根本原因就是对象的地址发生了改变)
// 对象在变和对象的属性再变是两回事
public void test3() {
synchronized ((Integer)ticketNums) {
if(ticketNums<0) {
flag=false;
return;
}
//模拟网络延时
try {
Thread.sleep(200);
//进入了阻塞状态,然后200s以后我就重新等待CPU的调用
//继续执行下面的代码
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}
//同步块 范围太大性能效率低下
public void test2() {
synchronized (this) {
if(ticketNums<0) {
flag=false;
return;
}
//模拟网络延时
try {
Thread.sleep(200);
//进入了阻塞状态,然后200s以后我就重新等待CPU的调用
//继续执行下面的代码
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}
//线程安全,同步
public synchronized void test1() {
if(ticketNums<0) {
flag=false;
return;
}
//模拟网络延时
try {
Thread.sleep(200);
//进入了阻塞状态,然后200s以后我就重新等待CPU的调用
//继续执行下面的代码
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}