Java------多线程_并发_同步_性能分析与影院例子(九)
同步块可以更小的锁定资源。
将之前的抢票案例修改一下
由同步方法,改为同步块格式。
该案例:线程由两个因素决定,分别是票数、和falg标识,但synchronized同步块只能锁一个内容。
因此需要包装。
案例一:
/**
* 线程安全:保证数据的安全性,同时效率尽可能高
* 第一个例子:抢票
* synchronized:同步块与同步方法,效率对比
*/
public class ThreadSyn04 {
public static void main(String[] args) {
UnSafe04 threadTest01 = new UnSafe04();
//多个代理,加入名称区分
new Thread(threadTest01,"thread01").start();
new Thread(threadTest01,"thread02").start();
new Thread(threadTest01,"thread03").start();
}
}
class UnSafe04 implements Runnable{
private int tickNums = 10;
private Boolean flag = true;
@Override
public void run(){
while (flag){
test();
}
}
//同步块,
public void test(){
synchronized(this){
if (tickNums<0){
flag = false;
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+tickNums--);
}
}
}
但是这个synchronized其实还是将方法内部全部锁住,和synchronized方法没有什么区别。而
改成这样,只锁flag又锁不住,还会造成线程不安全的情况。
锁的大了,造成性能下降,锁的区域小了,线程又不安全。
synchronized(this){
if (tickNums<0){
flag = false;
return;
}
}
粒度更小,保证数据的完整性
//同步块,
public void test(){
//尽可能锁定合理的范围(不是指代码,而是指数据的完整性)
//double checking
if (tickNums<=0){
flag = false; //考虑的是没有票的情况,不用判断
return;
}
synchronized(this){
if (tickNums<=0){
flag = false; //考虑最后一张票的情况,粒度更小
return;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+tickNums--);
}
}
案例二影院订票:
/**
* 快乐影院例子
*/
public class ThreadSyn05 {
public static void main(String[] args) {
Cinema cinema = new Cinema(100,"我的影院");
Customer customer = new Customer(cinema,80);
Customer customer2 = new Customer(cinema,80);
new Thread(customer).start();
new Thread(customer2).start();
}
}
//影院 Cinema
class Cinema{
public int avaliabe; //可用位置
public String name; //名称
public Cinema(int avaliabe, String name) {
this.avaliabe = avaliabe;
this.name = name;
}
//购票
public boolean bookTickets(int seats){
System.out.println("可用位置为:"+avaliabe);
if (seats > avaliabe){
return false;
}else {
avaliabe -= seats;
return true;
}
}
}
//顾客
class Customer implements Runnable{
Cinema cinema; //账户
int seats;//位置
public Customer(Cinema cinema,int seats){
this.cinema = cinema;
this.seats = seats;
}
@Override
public void run() {
boolean flag;
synchronized (cinema){
flag = cinema.bookTickets(seats);
if (flag){
System.out.println("出票成功:"+Thread.currentThread().getName()+"---位置为:"+seats);
}else {
System.out.println("出票失败"+ Thread.currentThread().getName()+"---位置不够");
}
}
}
}
此时还不满足,选位子的情况,因此需要再完善。
如下:
import java.util.ArrayList;
import java.util.List;
/**
* 快乐影院例子
*/
public class ThreadSyn051 {
public static void main(String[] args) {
List<Integer> cinemaList = new ArrayList<>();
cinemaList.add(1);
cinemaList.add(2);
cinemaList.add(3);
cinemaList.add(5);
cinemaList.add(8);
cinemaList.add(9);
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
List<Integer> list2 = new ArrayList<>();
list2.add(7);
list2.add(9);
Cinema1 cinema = new Cinema1(cinemaList,"我的影院");
Customer1 customer = new Customer1(cinema,list1);
Customer1 customer2 = new Customer1(cinema,list2);
new Thread(customer).start();
new Thread(customer2).start();
}
}
//影院 Cinema
class Cinema1{
public List<Integer> avaliabe; //可用位置
public String name; //名称
public Cinema1(List<Integer> avaliabe, String name) {
this.avaliabe = avaliabe;
this.name = name;
}
//购票
public boolean bookTickets(List<Integer> seats){
System.out.println("可用位置为:"+avaliabe);
if (seats.size() > avaliabe.size()){
return false;
}
List<Integer> copy = new ArrayList<>();
//赋值
copy.addAll(avaliabe);
//相减
copy.removeAll(seats);
//判断座位是否足够
if (avaliabe.size() - copy.size() != seats.size()){
return false;
}
//赋值
avaliabe = copy;
return true;
}
}
//顾客
class Customer1 implements Runnable{
Cinema1 cinema; //账户
List<Integer> seats;//位置
public Customer1(Cinema1 cinema,List<Integer> seats){
this.cinema = cinema;
this.seats = seats;
}
@Override
public void run() {
boolean flag;
synchronized (cinema){
flag = cinema.bookTickets(seats);
if (flag){
System.out.println("出票成功:"+Thread.currentThread().getName()+"---位置为:"+seats);
}else {
System.out.println("出票失败"+ Thread.currentThread().getName()+"---位置不够");
}
}
}
}