javase-day10

aSynchronizedScope_01SynchronizedDemo

package com.se.aSynchronizedScope;

/**
 * synchronized的作用域:
 *   1. synchronized可以锁住方法里面的部分代码,即锁的范围就是同步块的范围
 *       此时,锁对象可以是java的任何引用类型的对象
 *   2. 非静态方法上锁:在方法上添加synchronized关键字
 *       - 当一个线程访问该方法时,获得了锁,其他方法想要访问该方法处于等待状态
 *       - 多个线程访问的对象实例,必须是同一个方法,比如下面的桌子,必须是同一张
 *       - 当一个线程正在访问一个同步方法时,this这个锁对象即被他所占用,其他线程
 *         想要执行该线程的其他同步方法时,也需要等待,因为this锁已经被占用了
 */

public class _01SynchronizedDemo {
    public static void main(String[] args) {
        Desk desk = new Desk();
        Thread t1 = new Thread(desk, "小明");
        Thread t2 = new Thread(desk, "小红");
        t1.start();
        t2.start();
    }
}

class Desk implements Runnable {
    //添加一个非静态属性,充当锁对象
    Object obj = new Object();

    private int BeanCount = 10;

    //整体上锁,不需要特意制定锁对象,锁对象是this
    //public synchronized void take() {
    public void take() {
        System.out.println("开始拿豆子");
        //部分上锁
        synchronized (obj) {
            if (BeanCount > 0) {
                BeanCount--;
            }
        }
        System.out.println("一个豆子被拿走了");
    }

    public void run() {
        while (true) {
            take();
        }
    }


}

aSynchronizedScope_02StaticSynchronizedDemo

package com.se.aSynchronizedScope;


import sun.awt.image.ImageWatched;

import java.util.LinkedList;
import java.util.List;

public class _02StaticSynchronizedDemo {
    public static void main(String[] args) {
        //创建一个集合对象,存储五个线程
        List<Thread> pool = new LinkedList<Thread>();

        for (int i = 0; i < 5; i++) {
            Thread t = new Thread() {
                public void run() {
                    Boss b = Boss.getInstance();
                }
            };
            pool.add(t);
        }
        for (Thread t : pool) {
            t.start();
        }
    }
}
/**
 * 单例设计模式的懒汉模式
 *  1. 单例模式:在整个项目中,获取的对象是同一个
 *  2. 饿汉模式:着急获取对象的唯一实例、
 *  3. 懒汉模式:什么时候获取对象,什么时候创建对象
 */
class Boss {
    //第一步,提供一个私有的静态的该类的成员变量
    private static Boss instance;

    //第二步,构造器私有化
    private Boss() {
    }

    /*
      第三步,提供一个共有的静态的返回该类型的方法
      给静态方法上锁,就是在方法上添加修饰词
      锁对象是类名.class,这个类对象在整个项目下都是唯一的
     */
    public synchronized static Boss getInstance() {
        //synchronized (Boss.class) {
            if (instance == null) {
                instance = new Boss();
            }
        //}
        return instance;
    }
}

bDeadLock_01DeadLockDemo

package com.se.bDeadLock;

/**
 * 死锁的产生之一:
 *   线程A 先获取锁A,然后想要获取锁B
 *   线程B 先获取锁B,然后想要获取锁A
 *
 *   两个线程都占用了对方想要的锁,且对方还占用并不释放,
 *   因此都出现了等待,无发继续向下执行,这就是死锁
 */

public class _01DeadLockDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread("小明") {
            public void run() {
                synchronized ("A") {
                    for (int i = 0; i < 50; i++) {
                        System.out.println(getName() + ":" + i);
                    }
                    synchronized ("B") {
                        for (int i = 50; i < 100; i++) {
                            System.out.println(getName() + ":" + i);
                        }
                    }
                }
            }
        };
        Thread t2 = new Thread("小红") {
            public void run() {
                synchronized ("B") {
                    for (int i = 0; i < 50; i++) {
                        System.out.println(getName() + ":" + i);
                    }
                    synchronized ("A") {
                        for (int i = 50; i < 100; i++) {
                            System.out.println(getName() + ":" + i);
                        }
                    }
                }
            }
        };
        t1.start();
        t2.start();
    }
}

bDeadLock_02DeadLockDemo

package com.se.bDeadLock;

/**
 * 避免死锁的的方式之一:
 *   1. 按顺序加锁
 *   2. 设置超时等待,设置了一定时间显示,
 *       如果在这个时间范围内,没有获取到锁,那就不执行锁中的内容
 */

public class _02DeadLockDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread("小明") {
            public void run() {
                synchronized ("A") {
                    for (int i = 0; i < 50; i++) {
                        System.out.println(getName() + ":" + i);
                    }
                    synchronized ("B") {
                        for (int i = 50; i < 100; i++) {
                            System.out.println(getName() + ":" + i);
                        }
                    }
                }
            }
        };
        Thread t2 = new Thread("小红") {
            public void run() {
                synchronized ("A") {
                    for (int i = 0; i < 50; i++) {
                        System.out.println(getName() + ":" + i);
                    }
                    synchronized ("B") {
                        for (int i = 50; i < 100; i++) {
                            System.out.println(getName() + ":" + i);
                        }
                    }
                }
            }
        };
        t1.start();
        t2.start();
    }
}


cLockApi_01LockApiDemo

package com.se.cLockApi;

/**
 * 与锁有关的方法:
 *  1. wait(): 释放自己占有的锁对象,进入等待状态,不参与锁和时间片的争抢,
 *               直到被notify()或notifyAll()方法, 注意是锁调用该方法
 *     wait(long timeout): 等待一定时间,如果超时,则自动唤醒
 *     wait(long timeout, int nanos): 等待一定时间(时间更精确),如果超时,则自动唤醒
 *  2. notify():
 *        通知,唤醒等待队列中的某一线程,随机唤醒,被唤醒的那个线程进入锁池状态,开始争抢锁对象
 *  3. notifyAll():
 *        通知,唤醒等待队列中的所有线程,被唤醒的所有线程进入锁池状态,开始争抢锁对象
 */

public class _01LockApiDemo {
    public static void main(String[] args) {
        //创建锁对象
        Object obj = new Object();
        //定义一个下载线程
        Thread down = new Thread(() -> {
            System.out.println("开始下载");
            for (int i = 1; i < 101; i++) {
                String name = Thread.currentThread().getName();
                System.out.println(name + "下载了" + i + "%");
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("下载完成");
            synchronized (obj) {
                //如果想要调用锁的wait方法,必须先获得锁对象,然后在调用锁对象的wait方法
                obj.notify();
            }
        }, "下载图片");

        //定义一个显示线程
        Thread show = new Thread(() -> {
            //该显示线程,刚要执行任务时,就应该进入等待队列,因为等待下载线程结束
            try {
                synchronized (obj) {
                    //如果想要进入等待队列,必须先获得锁对象,然后在调用锁对象的wait方法
                    obj.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //当下载线程结束,该线程得到通知,才有机会获取锁对象,然后执行
            System.out.println("开始显示");
            for (int i = 1; i < 101; i++) {
                String name = Thread.currentThread().getName();
                System.out.println(name + "显示了" + i + "%");
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("显示完成");
        }, "显示图片");
        down.start();
        show.start();
    }
}

dReentrantLock_01ReentrantLockDemo

package com.se.dReentrantLock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * ReentrantLock: 是一个可以让一个线程多次获取锁对象的类型,里面内置一个计时器
 *                用于记录当前线程获取该所的次数,可以避免死锁
 *   1. 该类提供了两个子类型:
 *      非公平类:多个线程获取锁的方法,不是按照线程的请求顺序,而是可能发生"插队"现象
 *               这种锁,性能高,但是可能增加线程饥饿现象(某一个线程可能很久都获取不到锁)
 *       公平锁: 多个线程获取锁的方式,是按照请求顺序获取。谁都能获取到锁。减少了线程饥饿现象,
 *                 但是系统的吞吐量可能不高(性能高的线程也需要排队才能获取锁。)
 *       如何使用两种锁:
 *          构造器中传入true,表示公平锁,传入false或者不指定参数,使用的就是非公平锁、
 *   2. 该类比synchronized更灵活,但是需要手动上锁和解锁。
 *      lock(): 上锁方法,锁对象没有被其他线程占用时,就会上锁成功,否则当前线程处于阻塞状态,
 *      unlock(): 解锁方法,必须占用锁,才能解锁成功,释放锁,否则会抛出异常。
 *      tryLock(): 尝试获取锁,如果获取不到,并不阻塞,而是执行其他代码。
 *                  获取不到锁的时候,会返回false,否则返回true。
 *      tryLock(long time, TimeUnit unit):
 *                    可以指定一定时间获取锁对象,如果超出这个时间,还没获取到锁,就返回false。
 *                    时间内获得到锁,就返回true。
 */

public class _01ReentrantLockDemo {
    public static void main(String[] args) {
        //使用两个线程来模拟两个人使用计数器
        MyCounter1 counter = new MyCounter1("秒表");
        Thread t1 = new Thread(counter, "小明");
        Thread t2 = new Thread(counter, "小红");
        t1.start();
        t2.start();

    }
}

class MyCounter implements Runnable {
    private int count = 0;
    private String name;

    public MyCounter(String name) {
        this.name = name;
    }

    //先创建锁对象,构造器中可以传入一个参数,true表示公平锁,false表示非公平锁
    ReentrantLock rl = new ReentrantLock(true);

    public void run() {
        //调用lock方法进行上锁
        for (int i = 0; i < 100; i++) {
            rl.lock();
            count++;
            System.out.println(Thread.currentThread().getName() + "使用了秒表进行计数:" + count);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //同步代码块执行完后需要解锁,给其他线程获得锁的机会
        rl.unlock();
    }
}

dReentrantLock_02ReentrantLockDemo

package com.se.dReentrantLock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁的标准写法: 释放锁操作在finally模块里
 */

public class  _02ReentrantLockDemo  {
    public static void main(String[] args) {
        //使用两个线程来模拟两个人使用计数器
        MyCounter1 counter = new MyCounter1("秒表");
        Thread t1 = new Thread(counter,"小明");
        Thread t2 = new Thread(counter, "小红");
        t1.start();
        t2.start();

    }
}

class MyCounter1 implements Runnable {
    private int count = 0;
    private String name;

    public MyCounter1(String name) {
        this.name = name;
    }

    //先创建锁对象,构造器中可以传入一个参数,true表示公平锁,false表示非公平锁
    ReentrantLock rl = new ReentrantLock(true);
    public void run() {
        //调用lock方法进行上锁
        for (int i = 0; i < 100; i++) {
            rl.lock();
            count++;
            System.out.println(Thread.currentThread().getName() + "使用了秒表进行计数:" + count);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        /*
          如果在释放锁之前发生异常,锁就无法释放,别的线程就无法得到锁对象,处于阻塞状态
          因为为了不阻塞其他线程对锁的获取,那么当前线程不管是否有异常,都应该正确的释放锁
          所以,锁的释放,应该放在finally中
         */
        try {
            String str = null;
            System.out.println(str.length());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            //同步代码块执行完后需要解锁,给其他线程获得锁的机会
            rl.unlock();
        }
    }
}

dReentrantLock_03TicketCenterDemo

package com.se.dReentrantLock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 多个人进行购票
 */

public class _03TicketCenterDemo {
    public static void main(String[] args) {

        TicketCenter center = new TicketCenter(100);

        Thread t1 = new Thread(() -> {
            center.buyOne();
        }, "A");
        Thread t2 = new Thread(() -> {
            center.buyOne();
        }, "B");
        Thread t3 = new Thread(() -> {
            try {
                center.buyBatch(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "C");
        Thread t4 = new Thread(() -> {
            try {
                center.buyBatch(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "D");
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

class TicketCenter {
    private int ticketNum;

    public TicketCenter(int ticketNum) {
        this.ticketNum = ticketNum;
    }

    //获取一个锁对象
    ReentrantLock rl = new ReentrantLock();

    //购买一张高铁票
    public void buyOne() {
        //尝试获取锁对象
        boolean success = rl.tryLock();
        if (success) {
            System.out.println(Thread.currentThread().getName() + "当前票的数量是:" + ticketNum);
            if (ticketNum > 0) {
                try {
                    Thread.sleep(5000); //模拟购票的时间
                    ticketNum--;
                    System.out.println(Thread.currentThread().getName() + "购票成功,当前票的数量是:" + ticketNum);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    rl.unlock();
                }
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "没有获得锁对象,购票失败");
        }
    }

    //批量购买高铁票
    public void buyBatch(int num) throws InterruptedException {
        //尝试获取锁对象
        boolean success = rl.tryLock(10, TimeUnit.SECONDS);
        if (success) {
            System.out.println(Thread.currentThread().getName() + "当前票的数量是:" + ticketNum);
            if (ticketNum > 0 && ticketNum >= num) {
                try {
                    Thread.sleep(10000); //模拟购票的时间
                    ticketNum -= num;
                    System.out.println(Thread.currentThread().getName() + "购票成功,当前票的数量是:" + ticketNum);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    rl.unlock();
                }
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "没有获得锁对象,购票失败");
        }
    }
}

eProducerConsumerModel_PCModelDemo

package com.se.eProducerConsumerModel;

import java.util.LinkedList;
import java.util.List;

/**
 *  生产者消费者设计模式:
 *    1. 多线程并发的一种经典设计模式
 *    2. 多个生产者-一个仓库-多个消费者。
 *        仓库数据不足时生产者生产数据,存储到仓库,通知消费者进行消费
 *        仓库数据充足时消费者消费数据,从仓库中取出数据,不足时,通知生产者生产数据
 *    3. 这种模式的优点:
 *        - 解耦:消费者和生产者没有耦合度
 *        - 支持并发:多个生产者和多个消费者,可以并发执行
 *        - 支持忙闲不均:因为有仓库,生产过快可以存入仓库,让消费者慢慢处理数据
 */
public class PCModelDemo {
    public static void main(String[] args) {
        //创建一个苹果架子
        AppleShelf as = new AppleShelf(100);
        //创建四个生产者
        Producer p1 = new Producer(as, 30, "A");
        Producer p2 = new Producer(as, 40, "B");
        Producer p3 = new Producer(as, 50, "C");
        Producer p4 = new Producer(as, 60, "D");
        //创建七个消费者
        Consumer c1 = new Consumer(as, 20, "J");
        Consumer c2 = new Consumer(as, 70, "O");
        Consumer c3 = new Consumer(as, 60, "K");
        Consumer c4 = new Consumer(as, 40, "L");
        Consumer c5 = new Consumer(as, 50, "M");
        Consumer c6 = new Consumer(as, 30, "N");
        Consumer c7 = new Consumer(as, 70, "P");

        p1.start();
        p2.start();
        p3.start();
        p4.start();

        c1.start();
        c2.start();
        c3.start();
        c4.start();
        c5.start();
        c6.start();
        c7.start();
    }

}

//定义一个生产者
class Producer extends Thread {
    //要操作的架子
    private AppleShelf appleshelf;
    //生产苹果的数量
    private int num;

    public Producer(AppleShelf appleshelf, int num, String name) {
        super(name);
        this.appleshelf = appleshelf;
        this.num = num;
    }

    //生产者的任务代码
    public void run() {
        while (true) {
            produce();
        }
    }

    public void produce() {
        appleshelf.store(num);
    }
}

//定义一个消费者
class Consumer extends Thread {
    //要操作的架子
    private AppleShelf appleshelf;
    //要消费的苹果数量
    private int num;

    public Consumer(AppleShelf appleshelf, int num, String name) {
        super(name);
        this.appleshelf = appleshelf;
        this.num = num;
    }

    public void run() {
        while (true) {
            consumer();
        }
    }

    public void consumer() {
        appleshelf.take(num);
    }
}


//苹果架子,存储苹果
class AppleShelf {
    //定义一个容器,存储苹果
    private List<Apple> list;
    //定义一个容器属性
    private int capacity;

    public AppleShelf(int capacity) {
        list = new LinkedList<>();
        this.capacity = capacity;
    }

    //向苹果架子上放入苹果,由生产者调用  num为苹果数量
    public synchronized void store(int num) {
        //不能生产的条件
        while (list.size() + num > capacity) {
            try {
                //释放锁,进入等待队列
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //可以生产
        for (int i = 0; i < num; i++) {
            list.add(new Apple());
        }
        System.out.println(Thread.currentThread().getName() + "生产了" + num + "个苹果,现有" + list.size());
        //通知其他等待线程
        this.notifyAll();
    }

    //从苹果架子上取出苹果,由消费者调用  num为苹果数量
    public synchronized void take(int num) {
        //不能消费的条件
        while (list.size() < num) {
            //通知其他等待线程
            this.notifyAll();
            try {
                //释放锁,进入等待队列,循环判断
                System.out.println(Thread.currentThread().getName() + "需要" + num + "个苹果,剩余" + list.size());
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //可以消费
        int count = list.size();
        for (int i = count - 1; i >= count - num; i--) {
            list.remove(i);
        }
        System.out.println(Thread.currentThread().getName() + "消费了" + num + "个苹果,剩余" + list.size());
    }
}

class Apple {
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值