java.util 工具包 包 分类
业务:普通线程代码 Thread
Runable 没有返回值、效率相比于Callable较低
进程:一个程序 QQ.exe mUSIC.exe 程序的集合
一个进程往往包含多个进程 至少包含一个!
Java默认有几个线程? 2个:?main GC
对于java而言 开辟线程的方式 Thread Runnable Callable
Java可以开启线程吗? 不可以
源码:
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
//本地的方法调用native 操作系统底层的C++? java 无法直接直接操作硬件
并发(多线程操作同一个资源)
--?CPU一核? 快速交替
并行(多个人一起行走)
-- CPU多核 多个线程可以同时执行;
package com.xmx.demo1;
public class Test1 {
public static void main(String[] args) {
//获取cpu的核数
//CPU密集型 IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
并发编程的本质:充分利用cpu的资源
* @see #getState
*/
public enum State {
//新生
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待 死死的等
WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}
1)、来自不同的类
wait -> Object
sleep -> Thread
工作中用休眠大多是 TimeUnit
2)、关于锁的释放
wait会释放锁? ?sleep睡觉了? 抱着锁 不会释放
3)、使用的范围不同
wait 必须在同步代码块中
sleep可以在任何地方睡
4)、是否需要捕获异常
wait不需要 (现在也需要?)
sleep不需要
Synchronized(传统)? 解决票超卖问题
package com.xmx.demo1;
//基本的买票例子
/**
* 真正的多线程开发 公司中在用 降低耦合性
* 线程就是一个单独的资源类 没有任何的附属操作
*/
public class SaleTicketDemo1 {
public static void main(String[] args) {
//并发 多个线程操作同一个资源类 将资源类丢入线程
Ticket ticket = new Ticket();
//@FunctionalInterface函数式接口
new Thread(() -> {
for (int i = 1; i < 40; i++) {
ticket.sale();
}
},"A").start();
new Thread(() -> {
for (int i = 1; i < 40; i++) {
ticket.sale();
}
},"B").start();
new Thread(() -> {
for (int i = 1; i < 40; i++) {
ticket.sale();
}
},"C").start();
}
}
//资源类
class Ticket{
//属性 方法
private int number = 30;
//买票的方式
//synchronized 本质:队列 锁
public synchronized void sale(){
if(number > 0){
System.out.println(Thread.currentThread().getName() + "卖出" + number-- + "张票,剩余:" + number);
}
}
}
公平锁 非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁:十分公平? 先来后到
非公平锁:不公平 可以插队(默认)
package com.xmx.demo1;
//基本的买票例子
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 真正的多线程开发 公司中在用 降低耦合性
* 线程就是一个单独的资源类 没有任何的附属操作
*/
public class SaleTicketDemo2 {
public static void main(String[] args) {
//并发 多个线程操作同一个资源类 将资源类丢入线程
Ticket2 ticket2 = new Ticket2();
//@FunctionalInterface函数式接口
new Thread(() -> { for (int i = 1; i < 40; i++) ticket2.sale(); },"A").start();
new Thread(() -> { for (int i = 1; i < 40; i++) ticket2.sale(); },"B").start();
new Thread(() -> { for (int i = 1; i < 40; i++) ticket2.sale(); },"C").start();
}
}
//资源类
class Ticket2{
//属性 方法
private int number = 30;
Lock lock = new ReentrantLock();
//买票的方式
//synchronized 本质:队列 锁
public synchronized void sale(){
lock.lock();//加锁
try {
//业务代码
if(number > 0){
System.out.println(Thread.currentThread().getName() + "卖出" + number-- + "张票,剩余:" + number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//解锁
}
}
}
1)Synchronized 是内置的java关键字 ; 而Lock是一个java类
2)Synchronized 无法判断获取锁的状态; lock可以判断是否得到锁
3)Synchronized 会自动适放锁;? lock必须手动释放? 不是反 会导致死锁
4)Synchronized 线程 1(获得锁、阻塞)线程 2(一直等);lock就不一定会等下去
5)Synchronized 可重入锁 不可中断 非公平;Lock可重入锁 可以判断锁 非公平(可设置)
6)Synchronized 适合锁少量的代码同步问题;而Lock适合大量
package com.xmx.ProCon;
/**
* 线程之间的通信问题:生产者和消费者问题
* 线程交替执行 A B 操作同一个变量 num = 0
* A = num + 1
* B = nmu - 1
*/
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//判断等待 业务 通知
class Data{//数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
if(number != 0){
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "->" + number);
//通知其他线程 +1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
if(number == 0){
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "->" + number);
//通知其他线程 -1完毕
this.notifyAll();
}
}
问题存在? A B C D 线程呢?? 虚假唤醒
将if判断改为while判断
原因:wait()等待时进入多个线程?if只会判断一次? ;而while()循环会对每个线程唤醒重新判断
package com.xmx.ProCon;
/**
* 线程之间的通信问题:生产者和消费者问题
* 线程交替执行 A B 操作同一个变量 num = 0
* A = num + 1
* B = nmu - 1
*/
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//判断等待 业务 通知
class Data{//数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
while(number != 0){
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "->" + number);
//通知其他线程 +1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while(number == 0){
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "->" + number);
//通知其他线程 -1完毕
this.notifyAll();
}
}
传统的和现在的
通过Lock可以找到? Condition? ?取代了notify和wait 替代同步监视器?; lock取代了synchronized
代码实现
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
代码
package com.xmx.ProCon;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//线程顺序执行
public class C {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printA();
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printB();
}
},"B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printC();
}
},"C").start();
}
}
class Data3{ //资源类 lock
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1; //1A 2B 3C
public void printA(){
lock.lock();
try {
//业务代码 判断 执行 通知
while(number != 1){
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName() + " = A线程");
//唤醒指定的人 B
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
//业务代码 判断 执行 通知
while(number != 2){
//等待
condition2.await();
}
System.out.println(Thread.currentThread().getName() + " = B线程");
//唤醒指定的人 B
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
//业务代码 判断 执行 通知
while(number != 3){
//等待
condition3.await();
}
System.out.println(Thread.currentThread().getName() + " = C线程");
//唤醒指定的人 B
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
输出结果
如何判断锁的是谁?? 永远的知道什么锁? 锁到底所得是谁?
对象、class
1)代码演示
package com.xmx.lock8;
import java.util.concurrent.TimeUnit;
/**
* 8锁就是锁的八个问题
* 1、标准情况下 : 先发短信 在打电话
* 2、发短信方法中延迟4秒 : 结果依然是先发短信 在打电话
*/
public class Test1 {
public static void main(String[] args) {
phone phone = new phone();
new Thread(() -> {
phone.sendMes();
},"A").start();
// 捕获休眠
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
},"B").start();
}
}
class phone{
//synchronized 锁得对象是方法的调用者
//两个方法用的是同一个锁 先得到的先执行
public synchronized void sendMes(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送短信..");
}
public synchronized void call(){
System.out.println("拨打电话..");
}
}
结果:
2)代码
package com.xmx.lock8;
import java.util.concurrent.TimeUnit;
/**
* 3、增加一个新的方法 在phone中 不加synchronized
*/
public class Test2 {
public static void main(String[] args) {
phone2 phone2 = new phone2();
new Thread(() -> {
phone2.sendMes();
},"A").start();
// 捕获休眠
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.hello();
},"B").start();
}
}
class phone2{
//synchronized 锁得对象是方法的调用者
//两个方法用的是同一个锁 先得到的先执行
public synchronized void sendMes(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送短信..");
}
public synchronized void call(){
System.out.println("拨打电话..");
}
//同步方法 不受锁得影响
public void hello(){
System.out.println("hello!");
}
}
结果:
3)代码 new两个对象
package com.xmx.lock8;
import java.util.concurrent.TimeUnit;
/**
* 3、增加一个新的方法 在phone中 不加synchronized
*/
public class Test2 {
public static void main(String[] args) {
phone2 phone1 = new phone2();
phone2 phone2 = new phone2();
new Thread(() -> {
phone1.sendMes();
},"A").start();
// 捕获休眠
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
},"B").start();
}
}
class phone2{
//synchronized 锁得对象是方法的调用者
//两个方法用的是同一个锁 先得到的先执行
public synchronized void sendMes(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送短信..");
}
public synchronized void call(){
System.out.println("拨打电话..");
}
//同步方法 不受锁得影响
public void hello(){
System.out.println("hello!");
}
}
结果:
4)代码? 将前面的方法添加static
静态方法? 类一加载就有了? 锁的是Class 模板
package com.xmx.lock8;
import java.util.concurrent.TimeUnit;
/**
* 5、将两个方法改为静态 只有一个对象
*/
public class Test3 {
public static void main(String[] args) {
phone3 phone1 = new phone3();
new Thread(() -> {
phone1.sendMes();
},"A").start();
// 捕获休眠
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
},"B").start();
}
}
class phone3{
public static synchronized void sendMes(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送短信..");
}
public static synchronized void call(){
System.out.println("拨打电话..");
}
}
结果:
5)代码? 在方法添加了static的基础上 在new一个对象
两个对的class类模板只有一个 而static锁得 就是class模板
package com.xmx.lock8;
import java.util.concurrent.TimeUnit;
/**
* 5、将两个方法改为静态 只有一个对象
*/
public class Test3 {
public static void main(String[] args) {
phone3 phone1 = new phone3();
phone3 phone2 = new phone3();
new Thread(() -> {
phone1.sendMes();
},"A").start();
// 捕获休眠
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
},"B").start();
}
}
class phone3{
public static synchronized void sendMes(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送短信..");
}
public static synchronized void call(){
System.out.println("拨打电话..");
}
}
结果:
6) 代码? 一个对象 一个静态同步方法(发短信方法? 延迟4s)? 一个普通同步方法(注意)
package com.xmx.lock8;
import java.util.concurrent.TimeUnit;
/**
* 5、将两个方法改为静态 只有一个对象
*/
public class Test4 {
public static void main(String[] args) {
phone4 phone1 = new phone4();
new Thread(() -> {
phone1.sendMes();
},"A").start();
// 捕获休眠
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
},"B").start();
}
}
class phone4{
//静态的同步方法 锁的是class模板
public static synchronized void sendMes(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发送短信..");
}
//普通的同步方法 锁的是调用者
public synchronized void call(){
System.out.println("拨打电话..");
}
}
结果: 两个方法用的不是同一个锁? 因此后面的方法执行不会受前面的延时方法的影响
继续上面的补充:在new一个phone 执行打电话方法? 原先的还是执行发短信
输出依然不变!!!!!!!!!!!!
new this 具体的一个phone
static Class 唯一的模板
代码
package com.xmx.unsafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
//报错java.util.ConcurrentModificationException 并发修改异常
public class ListTest {
public static void main(String[] args) {
// List<String> list = Arrays.asList("1", "2", "3");
// list.forEach(System.out ::println);
/**
* 解决方案
* 1、List<String> list1 = new Vector<>();
* 2、List<String> list2 = Collections.synchronizedList(new ArrayList<>());
* 3、JUC 方案 import java.util.concurrent.CopyOnWriteArrayList;
* List<String> list3 = new CopyOnWriteArrayList<>();
*/
//并发下 ArrayList是不安全的
// List<String> list = new ArrayList<>();
// List<String> list1 = new Vector<>();
// List<String> list2 = Collections.synchronizedList(new ArrayList<>());
//写入时复制 cow 计算机程序设计领域的一种优化策略
//多个线程调用的时候 list 读取的时候是固定的 写入覆盖
//在写入得时候避免覆盖 造成数据问题
List<String> list3 = new CopyOnWriteArrayList<>();
for (int i = 1; i <= 10; i++) {
new Thread(() -> {
list3.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list3);
},String.valueOf(i)).start();
}
}
}
读写分离
CopyOnWriteArrayList 是 Java 并发包(java.util.concurrent)中的一个类,它是一个线程安全的 ArrayList。其设计目标是支持高并发访问,同时提供相对较低的写操作开销。
CopyOnWriteArrayList 的主要优势在于其对并发操作的处理。当你修改列表时(例如添加、删除元素),它会首先创建一个新数组,然后在该新数组上进行修改,最后将内部引用指向新数组。这个过程称为写时复制(Copy-on-Write)。
这种机制保证了以下特点:
但是,CopyOnWriteArrayList 也有其局限性:
总的来说,CopyOnWriteArrayList 的设计目标是提供一个线程安全的、读操作开销低、写操作开销高的数据结构,适用于读多写少的并发场景。
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
CopyOnWriteArrayList和Vector都是线程安全的集合类,但它们实现线程安全的方式和性能特点有所不同。
总的来说,CopyOnWriteArrayList适合读多写少的并发场景,而Vector更适合需要绝对线程安全的场景。
package com.xmx.unsafe;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 同理出现 报错java.util.ConcurrentModificationException 并发修改异常
* 解决方案
* 1、Set<String> set = Collections.synchronizedSet(new HashSet<>()); 工具类
* 2、Set<String> set = new CopyOnWriteArraySet<>(); JUC写入时复制
*/
public class SetTest {
public static void main(String[] args) {
// Set<String> set = new HashSet<>();
// Set<String> set = Collections.synchronizedSet(new HashSet<>());
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
hashset底层是什么?底层就是hashmap
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
//add? set本质就是map? key是不可以重复的? ?PRESENT是不变的 ??
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
代码
package com.xmx.unsafe;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* java.util.ConcurrentModificationException
*/
public class MapTest {
public static void main(String[] args) {
//map是这样用的吗 ? 不是,工作中不用hashmap
//默认等价于什么? new HashMap<>(16,0.75);
// Map<String, String> map = new HashMap<>();
Map<String, String> map = new ConcurrentHashMap<>();
//加载因子 初始容量
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
ConcurrentHashMap的原理?
ConcurrentHashMap 是 Java 并发包中的一个类,它是一个线程安全的哈希表实现。其原理主要包括以下几个方面:
通过以上原理,ConcurrentHashMap 提供了高并发、高性能的线程安全哈希表实现。它在 Java 并发编程中广泛应用,适用于需要处理大量并发读写操作的场景。
1)、可以有返回值
2)、可以抛出异常
3)、方法不同? call方法? runable为run方法
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
代码
package com.xmx.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// new Thread(new Runnable()).start();
// new Thread(new FutureTask<V>()).start();
// new Thread(new FutureTask<V>(Callable)).start();
new Thread().start();//如何启动Callable
MyThread thread = new MyThread();
FutureTask futureTask = new FutureTask(thread);//适配器
new Thread(futureTask,"A").start();
String o = (String)futureTask.get();//获取callable的返回结果
System.out.println(o);
}
}
class MyThread implements Callable<String> {
@Override
public String call() {
System.out.println("call()被执行..." );
return "123456";
}
}
上面的get方法可能会产生阻塞? ?将其放到最后一行? 或者使用异步处理
new Thread(futureTask,"A").start();
new Thread(futureTask,"B").start();
同时执行只会输出一次call? ??
原因:? 由于JVM第二次再次调用FutureTask对象所持有的线程
FutureTask的run方法:if (state != NEW || ...) return ;是没有执行
允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
代码
package com.xmx.add;
import java.util.concurrent.CountDownLatch;
//计数器
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//倒计时 总计数6 必须要执行的任务才使用
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
//数量减一
System.out.println(Thread.currentThread().getName() + "线程结束..");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await(); //等待计数器归零 继续向下执行
System.out.println("Close Door!");
}
}
down方法:? 减一操作
awiat方法 :??down方法减为0该方法被唤醒 !!!时继续向下执行
代码
package com.xmx.add;
import org.omg.PortableServer.THREAD_POLICY_ID;
import javax.print.AttributeException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
//召唤龙珠的线程
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() -> {
System.out.println("召唤神龙成功!");
});
for (int i = 1; i <=7 ; i++) {
final int temp = i;
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "收集" + temp + "颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
代码
package com.xmx.add;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo {
public static void main(String[] args) {
//线程数量: 停车位 限流
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <=6 ; i++) {
new Thread(() -> {
//acquire() 得到
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "抢到车位..");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "离开车位..");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
acquire获得? 已经满了等待被释放
realease 释放 将当前的信号释放量+1 然后唤醒等待的线程
补充
在Java中,java.util.concurrent.locks
包提供了几种不同类型的锁,其中最常用的两种是公平锁和非公平锁。
Java中的ReentrantLock
类支持公平锁。可以通过构造函数来指定是否为公平锁,例如:
java复制代码
ReentrantLock lock = new ReentrantLock(true); // 公平锁 |
Java中的ReentrantLock
类也支持非公平锁。与公平锁类似,可以通过构造函数来指定是否为非公平锁,例如:
java复制代码
ReentrantLock lock = new ReentrantLock(false); // 非公平锁 |
选择使用公平锁还是非公平锁取决于具体的应用场景。在某些情况下,公平锁可能更合适,例如当线程需要按照某种顺序执行时。在其他情况下,非公平锁可能更合适,例如当需要快速地获取和释放锁时。
我懂了,写锁会禁止其他写锁操作,也会禁止其他读锁,而读锁不会禁止其他读锁(这是和写锁有区别的,也是和sync的区别),同时禁止其他写锁
代码
package com.xmx.rw;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 独占锁就是写锁 一次只能一个线程占有
* 共享锁就是读锁 多个线程可以同时占有
* ReadWriteLock
* 读-读 可以共存
* 读-写 不能共存
* 写-写 不能共存
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
//只做写入的操作
for (int i = 1; i <= 5 ; i++) {
final int temp = i;
new Thread(() -> {
myCache.put(temp + "",temp + "");
},String.valueOf(i)).start();
}
//只做读取的操作
for (int i = 1; i <= 5 ; i++) {
final int temp = i;
new Thread(() -> {
myCache.get(temp + "");
},String.valueOf(i)).start();
}
}
}
/**
* 自定义缓存---加了锁的
*/
class MyCache{
private volatile Map<Object, Object> objectObjectHashMap = new HashMap<>();
//读写锁 更加细粒度的控制
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//存,写 希望只有一个线程写
public void put(String key,Object value){
//加锁
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "写入ing");
objectObjectHashMap.put(key,value);
System.out.println(Thread.currentThread().getName() + "写入OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
readWriteLock.writeLock().unlock();
}
}
//取,读 所与人都可以读
public void get(String key){
//加锁
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "读取ing");
objectObjectHashMap.get(key);
System.out.println(Thread.currentThread().getName() + "读取OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
readWriteLock.readLock().unlock();
}
}
}
///**
// * 自定义缓存 -- 不含锁
// */
//class MyCache{
// private volatile Map<Object, Object> objectObjectHashMap = new HashMap<>();
//
// //存,写
// public void put(String key,Object value){
// System.out.println(Thread.currentThread().getName() + "写入ing");
// objectObjectHashMap.put(key,value);
// System.out.println(Thread.currentThread().getName() + "写入OK");
//
// }
//
// //取,读
// public void get(String key){
// System.out.println(Thread.currentThread().getName() + "读取ing");
// objectObjectHashMap.get(key);
// System.out.println(Thread.currentThread().getName() + "读取OK");
//
// }
//}
FIFO先进先出,阻塞,队列写入:如果队列满了,就必须阻塞等待,取:如果阻塞是空的,就必须阻塞等待生成(不得不阻塞)
阻塞队列:
BlockingQueue?不是新的东西
阻塞队列的使用场景:多线程并发处理? ???线程池
学会使用队列
添加 移出
/**
* 抛出异常
*/
public static void test1(){
//队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
//抛出异常: java.lang.IllegalStateException: Queue full
//System.out.println(blockingQueue.add("d"));
System.out.println("===================================");
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
//抛出异常: java.util.NoSuchElementException
System.out.println(blockingQueue.remove());
}
查看队首元素
检测队首元素
没有容量?
进去一个元素 必须等取出来之后? 才能继续放下一个元素