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 {
}