Day42

并发 同步 性能分析

显然同步方法,直接锁住方法的对象 ,很精准,但会造成线程安全 范围太大---->效率低下的问题

换用同步块锁定 可以锁定特定的对象 但可能会出现线程不安全 ticketNums对象在变 锁不住的问题

锁定this即方法的对象 如果缩小锁定范围,可能会出现线程不安全 范围太小 锁不住的问题

因此我们应该尽可能的锁定合理的范围(不是指代码,指数据的完整性)

很多时候我们需要用到双重检查的问题 一般用来解决临界值的问题

虽然代码有所增多,但性能却有了很大的提升

if (ticketNums <= 0) {//考虑没有票的可能
flag = false;
return;
}
synchronized (this) {
if (ticketNums <= 0) {//考虑最后一张票
flag = false;
return;
}

package com.sxt.syn;

/**
 * 线程安全 :在并发时保证数据的准确性、效率尽可能高
 * synchronized
 * 1、同步方法
 * 2、同步块
 */
public class SynBlockTest03 {
        public static void main(String[] args) {
            //一份资源
            SynWeb12306 web = new SynWeb12306();
            //多个代理
            new Thread(web,"码畜").start();
            new Thread(web,"码农").start();
            new Thread(web,"码磺").start();
        }
    }

class SynWeb12306 implements Runnable {
    //票数
    private int ticketNums = 10;
    private boolean flag=true;

    @Override
    public void run() {
        while (flag) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            test05();
        }
    }
    //线程安全:尽可能锁定合理的范围(不是指代码,指数据的完整性)
    //double checking
    public void test05() {
        if (ticketNums <= 0) {//考虑没有票的可能
            flag = false;
            return;
        }
        synchronized (this) {
            if (ticketNums <= 0) {//考虑最后一张票
                flag = false;
                return;
            }
            //模拟网络延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---->" + ticketNums--);
        }
    }
    //线程不安全  范围太小 锁不住
    public void test04() {
        synchronized (this) {
            if (ticketNums <= 0) {
                flag = false;
                return;
            }
        }
            //模拟网络延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---->" + ticketNums--);
        }

    //线程不安全 ticketNums对象在变
    public void test03() {
        synchronized ((Integer)ticketNums) {
            if (ticketNums <= 0) {
                flag = false;
                return;
            }
            //模拟网络延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---->" + ticketNums--);
        }
    }
    //线程安全 范围太大---->效率低下
    public void test02() {
        synchronized (this) {
            if (ticketNums <= 0) {
                flag = false;
                return;
            }
            //模拟网络延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---->" + ticketNums--);
        }
    }
    //线程安全 同步
    public synchronized void test01(){
        if(ticketNums<=0){
            flag=false;
            return;
        }
        //模拟网络延时
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"---->"+ticketNums--);
    }
}
多线程_ 并发 _同步 _快乐影院

写一个顾客类一个影院类

影院类里有属性影院座位数、影院名称

影院类中写一个订票方法 如果订票数大于座位数,返回flase

不大于就是座位数减订票数返回目前座位数

顾客类重写Runnable接口,实现多线程

添加属性要去的影院、要买的座位数

run()中判断购票是否成功

synchronized利用方法块锁住影院

main()里实现两个线程并发

package com.sxt.syn;

/**
 * 快乐影院
 */
public class HappyCinema {
    public static void main(String[] args) {
        Cinema c = new Cinema(20,"快乐影院");
        new Thread(new Customer(c,2),"南疆").start();
        new Thread(new Customer(c,1),"宝").start();

    }
}

//顾客
class Customer implements Runnable{
    Cinema cinema;
    int seats;

    public Customer(Cinema cinema, int seats) {
        this.cinema = cinema;
        this.seats = seats;
    }

    @Override
    public void run() {
        synchronized (cinema){
            boolean flag = cinema.bookTickets(seats);
            if (flag) {
                System.out.println("出票成功" + Thread.currentThread().getName() + "-<位置为:" + seats);
            } else {
                System.out.println("出票失败" + Thread.currentThread().getName() + "-<位置不够");
            }
        }
    }
}

//影院
class  Cinema{
    int available;//可用的位置
    String name;//名称

    public Cinema(int available, String name) {
        this.available = available;
        this.name = name;
    }
    //订票
    public boolean bookTickets(int seats) {
        System.out.println("可用位置为:"+available);
        if (seats>available){
            return false;
        }
        available-=seats;
        return true;
    }
}

改造快乐影院,可以进行选票

添加容器

难在判断出票是否成功

将可用的位置拷贝一份,有人订票就调用copy.removeAll()减去位置

判断可用位置的容器量减去定完票的copy容器中的容量是否等于订票的容量,如果不相等return flase 相等的话就将copy的容量给影院位置

package com.sxt.syn;

import java.util.ArrayList;
import java.util.List;

/**
 * 快乐影院
 */
public class HappyCinema02 {
    public static void main(String[] args) {
        //可用的位置
        List<Integer> available=new ArrayList<Integer>();
        available.add(1);
        available.add(2);
        available.add(3);
        available.add(6);
        available.add(7);

        //顾客需要的位置
        List<Integer> seats1=new ArrayList<Integer>();
        seats1.add(1);
        seats1.add(6);
        List<Integer> seats2=new ArrayList<Integer>();
        seats2.add(2);
        seats2.add(3);
        seats2.add(4);
        SxtCinema c = new SxtCinema(available,"快乐影院");
        new Thread(new HappyCustomer(c,seats1),"南疆").start();
        new Thread(new HappyCustomer(c,seats2),"宝").start();

    }
}

//顾客
class HappyCustomer implements Runnable{
    SxtCinema cinema;
    List<Integer> seats;

    public HappyCustomer(SxtCinema cinema, List<Integer > seats) {
        this.cinema = cinema;
        this.seats = seats;
    }

    @Override
    public void run() {
        synchronized (cinema){
            boolean flag = cinema.bookTickets(seats);
            if (flag) {
                System.out.println("出票成功"+"\t" + Thread.currentThread().getName() + "-<位置为:" + seats);
            } else {
                System.out.println("出票失败"+"\t" + Thread.currentThread().getName() + "-<位置不够");
            }
        }
    }
}

//影院
class  SxtCinema{
    List<Integer> available;//可用的位置
    String name;//名称

    public SxtCinema(List<Integer> available, String name) {
        this.available = available;
        this.name = name;
    }
    public boolean bookTickets(List<Integer> seats) {
        System.out.println("欢迎光临"+this.name+"\n"+"当前可用位置为:" + available);
        List<Integer> copy = new ArrayList<Integer>();
        copy.addAll(available);

        //相减
        copy.removeAll(seats);
        //判断大小
        if (available.size()-copy.size()!=seats.size()){
            return false;
        }
        //成功
        available=copy;
        return true;
    }
}
/**
欢迎光临快乐影院
当前可用位置为:[1, 2, 3, 6, 7]
出票成功	南疆-<位置为:[1, 6]
欢迎光临快乐影院
当前可用位置为:[2, 3, 7]
出票失败	宝-<位置不够
*/

同步方法实现购票

同步方法写在火车票网里

顾客作为Thread的子类继承父类的Runnable target

在看是谁在购票时,我们可以将当前线程进行强转给子类顾客,通过顾客对象的调用判断是否购票成功

package com.sxt.syn;

/**
 * 快乐火车票
 */
public class Happy12306 {
    public static void main(String[] args) {
        Web12306 c = new Web12306(20,"快乐火车");
        new Passenger(c,"南疆",3).start();
        new Passenger(c,"宝哥",2).start();
    }
}
//顾客
class Passenger extends Thread{
    int seats;

    public Passenger (Runnable target,String name,int seats) {
        super(target,name);
        this.seats=seats;
    }
}

//火车票网
class Web12306 implements Runnable{
    int available;//可用的位置
    String name;//名称

    public Web12306(int available, String name) {
        this.available = available;
        this.name = name;
    }
    @Override
    public void run() {
        Passenger p=(Passenger) Thread.currentThread();
        boolean flag = false;
        try {
            flag = this.bookTickets(p.seats);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (flag) {
                System.out.println("出票成功" + Thread.currentThread().getName() + "-<位置为:" + p.seats);
            } else {
                System.out.println("出票失败" + Thread.currentThread().getName() + "-<位置不够");
            }
        }

    //购票
    public synchronized boolean bookTickets(int seats) throws InterruptedException {
        Thread.sleep(200);
        System.out.println("可用位置为:"+available);
        if (seats>available){
            return false;
        }
        available-=seats;
        return true;
    }
}

并发操作编程容器

juc的并发编程中 list 有对应的并发容器 直接供我们使用 内部已经实现好了锁定:CopyOnWriteArrayList list = new CopyOnWriteArrayList();

package com.sxt.syn;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 线程安全:操作并发容器
 */
public class SynContainer {
    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayList<String > list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i <1000 ; i++) {
            new Thread(()->{
              list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());
    }
}
/**
1000
*/
死锁

死锁:多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能进行,而导致两个或者多个线程都在等待着对方释放资源,都停止执行的情形。某一个同步块同时拥有“两个以上对象的锁”时,就可能发生“死锁"的问题。

化妆死锁问题

张柏芝拿着口红,王菲拿着镜子

互相都不放下,造成死锁

package com.sxt.syn;

/**
 * 死锁:过多的同步可能造成相互不释放资源
 * 从而相互等待,一般发生于同步中持有多个对象的锁
 */
public class DeadLock {
    public static void main(String[] args) {
        Markup g1 = new Markup(0,"张柏芝");
        Markup g2 = new Markup(1,"王菲");
        g1.start();
        g2.start();
    }
}
//口红
class Lipstick{

}
//镜子
class Mirror{

}
//化妆
class Markup extends Thread {
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    //选择
    int choice;
    //名字
    String girl;

    public Markup(int choice, String girl) {
        this.choice = choice;
        this.girl = girl;
    }

    @Override
    public void run() {
        //化妆
        markup();
    }

    //相互持有对象的对象锁---->可能造成死锁
    private void markup() {
        if (choice == 0) {
            synchronized (lipstick) {//获得口红的锁
                System.out.println(this.girl + "涂口红");
                //一秒后想拥有镜子的锁
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (mirror) {//获得口红的锁
                    System.out.println(this.girl + "照镜子");
                }
            }
        } else {
            synchronized (mirror) {//获得镜子的锁
                    System.out.println(this.girl + "照镜子");
                    //2秒后想拥有口红的锁
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lipstick) {//获得口红的锁
                        System.out.println(this.girl + "涂口红");
                    }
            }
        }
    }
}

解决死锁:避免:不要在同一个代码块中,同时持有多个对象的锁

禁止锁套锁

package com.sxt.syn;

/**
 * 死锁:过多的同步可能造成相互不释放资源
 * 从而相互等待,一般发生于同步中持有多个对象的锁
 *
 * 避免:不要在同一个代码块中,同时持有多个对象的锁
 */
public class DeadLock {
    public static void main(String[] args) {
        Markup g1 = new Markup(0,"张柏芝");
        Markup g2 = new Markup(1,"王菲");
        g1.start();
        g2.start();
    }
}
//口红
class Lipstick{

}
//镜子
class Mirror{

}
//化妆
class Markup extends Thread {
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    //选择
    int choice;
    //名字
    String girl;

    public Markup(int choice, String girl) {
        this.choice = choice;
        this.girl = girl;
    }

    @Override
    public void run() {
        //化妆
        markup();
    }

    //相互持有对象的对象锁---->可能造成死锁
    private void markup() {
        if (choice == 0) {
            synchronized (lipstick) {//获得口红的锁
                System.out.println(this.girl + "涂口红");
                //一秒后想拥有镜子的锁
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                /*synchronized (mirror) {//获得口红的锁
                    System.out.println(this.girl + "照镜子");
                }*/
            }
            synchronized (mirror) {//获得口红的锁
                System.out.println(this.girl + "照镜子");
            }
        } else {
            synchronized (mirror) {//获得镜子的锁
                    System.out.println(this.girl + "照镜子");
                    //2秒后想拥有口红的锁
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    /*synchronized (lipstick) {//获得口红的锁
                        System.out.println(this.girl + "涂口红");
                    }*/
            }
            synchronized (lipstick) {//获得口红的锁
                System.out.println(this.girl + "涂口红");
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值