继昨天学习了线程池之后,今天学习了多线程内的锁Lock。
定义方法:
ReentrantLock queueLock = new ReentrantLock(); //可重入锁
ReentrantReadWriteLock orderLock = new ReentrantReadWriteLock(); //可重入读写锁
每个锁都有个lock方法(上锁)和unlock方法(释放锁)
在写入锁的时候只能有一个线程,但是读取锁的时候可以线程一起共享锁里面的代码
今天还学习了信号量Semphore 自己定义最大可以同时运行多少线程
定义方法:
Semaphore placeSemaphore = new Semaphore(5);
使用acquire方法获得信号量 总信号量-1
使用release方法释放信号量 总信号量+1
附今日的代码:
1 import java.util.concurrent.locks.ReentrantLock; 2 import java.util.concurrent.locks.ReentrantReadWriteLock; 3 4 public class LockExample { 5 6 private static final ReentrantLock queueLock = new ReentrantLock(); //可重入锁 7 private static final ReentrantReadWriteLock orderLock = new ReentrantReadWriteLock(); //可重入读写锁 8 9 /** 10 * 有家奶茶店,点单有时需要排队 11 * 假设想买奶茶的人如果看到需要排队,就决定不买 12 * 又假设奶茶店有老板和多名员工,记单方式比较原始,只有一个订单本 13 * 老板负责写新订单,员工不断地查看订单本得到信息来制作奶茶,在老板写新订单时员工不能看订单本 14 * 多个员工可同时看订单本,在员工看时老板不能写新订单 15 * @param args 16 * @throws InterruptedException 17 */ 18 public static void main(String[] args) throws InterruptedException { 19 //buyMilkTea(); 20 handleOrder(); //需手动关闭 21 } 22 23 public void tryToBuyMilkTea() throws InterruptedException { 24 boolean flag = true; 25 while(flag) 26 { 27 //判断queneLock现在是什么状态,如果是锁住的状态就返回false,如果是空闲状态则将它锁住返回true。 28 if (queueLock.tryLock()) { 29 //queueLock.lock(); 30 //随机睡眠一段时间 31 long thinkingTime = (long) (Math.random() * 500); 32 Thread.sleep(thinkingTime); 33 System.out.println(Thread.currentThread().getName() + ": 来一杯珍珠奶茶,不要珍珠"); 34 flag = false; 35 //将锁释放 36 queueLock.unlock(); 37 } else { 38 //System.out.println(Thread.currentThread().getName() + ":" + queueLock.getQueueLength() + "人在排队"); 39 System.out.println(Thread.currentThread().getName() + ": 再等等"); 40 } 41 if(flag) 42 { 43 Thread.sleep(1000); 44 } 45 } 46 47 } 48 49 public void addOrder() throws InterruptedException { 50 //写入锁 锁住的情况下只能一个线程写 51 orderLock.writeLock().lock(); 52 //睡眠一段时间 53 long writingTime = (long) (Math.random() * 1000); 54 Thread.sleep(writingTime); 55 System.out.println("老板新加一笔订单"); 56 //释放锁 57 orderLock.writeLock().unlock(); 58 } 59 60 public void viewOrder() throws InterruptedException { 61 //读取锁 锁住的情况下可以多个线程一起共享 62 orderLock.readLock().lock(); 63 //睡眠一段时间 64 long readingTime = (long) (Math.random() * 500); 65 Thread.sleep(readingTime); 66 System.out.println(Thread.currentThread().getName() + ": 查看订单本"); 67 //释放锁 68 orderLock.readLock().unlock(); 69 70 } 71 72 //买奶茶方法 73 public static void buyMilkTea() throws InterruptedException { 74 LockExample lockExample = new LockExample(); 75 //定义线程数 76 int STUDENTS_CNT = 10; 77 //建立线程 78 Thread[] students = new Thread[STUDENTS_CNT]; 79 for (int i = 0; i < STUDENTS_CNT; i++) { 80 //给每个线程完成初始化 81 students[i] = new Thread(new Runnable() { 82 83 @Override 84 public void run() { 85 try { 86 //随机睡眠一段时间 87 long walkingTime = (long) (Math.random() * 1000); 88 Thread.sleep(walkingTime); 89 //尝试现在是否能够买奶茶 90 lockExample.tryToBuyMilkTea(); 91 } catch(InterruptedException e) { 92 System.out.println(e.getMessage()); 93 } 94 } 95 96 } 97 ); 98 //让所有线程开始工作 99 students[i].start(); 100 } 101 102 for (int i = 0; i < STUDENTS_CNT; i++) 103 //等待所有线程结束 104 students[i].join(); 105 106 } 107 108 109 public static void handleOrder() throws InterruptedException { 110 LockExample lockExample = new LockExample(); 111 112 //创建了一个老板写的线程类并且完成了初始化。 113 Thread boss = new Thread(new Runnable() { 114 115 @Override 116 public void run() { 117 while (true) { 118 try { 119 //添加订单 120 lockExample.addOrder(); 121 //随机睡眠一段时间 122 long waitingTime = (long) (Math.random() * 1000); 123 Thread.sleep(waitingTime); 124 } catch (InterruptedException e) { 125 System.out.println(e.getMessage()); 126 } 127 } 128 } 129 }); 130 //老板线程开始 131 boss.start(); 132 //定义员工线程数 133 int workerCnt = 3; 134 //创建员工线程 135 Thread[] workers = new Thread[workerCnt]; 136 for (int i = 0; i < workerCnt; i++) 137 { 138 //给每个员工线程初始化 139 workers[i] = new Thread(new Runnable() { 140 141 @Override 142 public void run() { 143 while (true) { 144 try { 145 //查看订单 146 lockExample.viewOrder(); 147 //睡眠一段时间 148 long workingTime = (long) (Math.random() * 5000); 149 Thread.sleep(workingTime); 150 } catch (InterruptedException e) { 151 System.out.println(e.getMessage()); 152 } 153 } 154 } 155 156 }); 157 //员工线程开始工作 158 workers[i].start(); 159 } 160 161 } 162 }
1 import java.util.concurrent.Semaphore; 2 3 public class SemaphoreExample { 4 //定义了5个车位 5 private final Semaphore placeSemaphore = new Semaphore(5); 6 7 public boolean parking() throws InterruptedException { 8 //如果此时Semaphore信号量不为0就会获取一个信号量返回true并且信号量-1,如果信号量为0的话则返回false 9 if (placeSemaphore.tryAcquire()) { 10 System.out.println(Thread.currentThread().getName() + ": 停车成功"); 11 return true; 12 } else { 13 System.out.println(Thread.currentThread().getName() + ": 没有空位"); 14 return false; 15 } 16 17 } 18 19 public void leaving() throws InterruptedException { 20 //释放掉一个信号量,信号量+1 21 placeSemaphore.release(); 22 System.out.println(Thread.currentThread().getName() + ": 开走"); 23 } 24 25 /** 26 * 现有一地下车库,共有车位5个,由10辆车需要停放,每次停放时,去申请信号量 27 * @param args 28 * @throws InterruptedException 29 */ 30 public static void main(String[] args) throws InterruptedException { 31 //定义总共要停车的数量 32 int tryToParkCnt = 10; 33 34 SemaphoreExample semaphoreExample = new SemaphoreExample(); 35 //创建要停车的数量的线程 36 Thread[] parkers = new Thread[tryToParkCnt]; 37 38 for (int i = 0; i < tryToParkCnt; i++) { 39 //将每个线程进行初始化 40 parkers[i] = new Thread(new Runnable() { 41 //这是视频里面的源代码,我在运行之后发现结果和我想象中的有点不同,因为有的车没有停到车位,不是等待之后再停车,而是直接没有停车了。 42 //原因是不管if里面返回true或是false都只会执行一次,如果是false的话就只输出了一个没有空位,然后线程就结束了。 43 //所以我在if判断的外面加了一个while死循环,当if为true,车成功的停车然后离开车位之后break退出循环。 44 // @Override 45 // public void run() { 46 // try { 47 // long randomTime = (long) (Math.random() * 1000); 48 // Thread.sleep(randomTime); 49 // if (semaphoreExample.parking()) { 50 // long parkingTime = (long) (Math.random() * 1200); 51 // Thread.sleep(parkingTime); 52 // semaphoreExample.leaving(); 53 // } 54 // } catch (InterruptedException e) { 55 // e.printStackTrace(); 56 // } 57 // } 58 @Override 59 public void run() { 60 try { 61 exit: 62 while(true) 63 { 64 //睡眠一段时间 65 long randomTime = (long) (Math.random() * 1000); 66 Thread.sleep(randomTime); 67 //尝试进行停车,如果停车成功会返回true 68 if (semaphoreExample.parking()) { 69 //睡眠一段时间,然后调用离开方法 70 long parkingTime = (long) (Math.random() * 1200); 71 Thread.sleep(parkingTime); 72 semaphoreExample.leaving(); 73 break exit; 74 } 75 } 76 } catch (InterruptedException e) { 77 e.printStackTrace(); 78 } 79 } 80 }); 81 //让每个线程开始工作 82 parkers[i].start(); 83 } 84 85 for (int i = 0; i < tryToParkCnt; i++) { 86 //等待每个线程结束 87 parkers[i].join(); 88 } 89 } 90 }