JUC
进程和线程
进程:
是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
线程:
是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
线程的状态
状态
public enum State {
/**
* 尚未启动的线程的状态。
*/
NEW,
/**
* 可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行,
* 但它可能正在等待来自操作系统的其他资源,比如处理器。
*/
RUNNABLE,
/**
* 等待监视器锁的阻塞线程的线程状态。处于阻塞状态的线程正在等待监视器锁进入同步块/方法,
* 或者在调用Object.wait后重新进入同步块/方法。
*/
BLOCKED,
/**
* 等待线程的线程状态。线程由于调用以下方法之一而处于等待状态:
* 对象。没有超时的等待
* 线程。不带超时的连接
* LockSupport.park 处于等待状态的线程正在等待另一个线程执行特定的操作。
* 例如,在一个对象上调用object. wait()的线程正在等待另一个线程在该对象上调用object. notify()或object. notifyall()。
* 调用了thread .join()的线程正在等待指定的线程结束。
* <p>
* 一直等
*/
WAITING,
/**
* 具有指定等待时间的等待线程的状态。由于调用了以下方法中的一个,并且指定了一个正的等待时间,
* 线程处于计时等待状态: thread . sleep
* 对象。等待与超时
* 线程。加入超时
* LockSupport.parkNanos LockSupport.parkUntil
* <p>
* 等待有超时时间
*/
TIMED_WAITING,
/**
* 终止线程的线程状态。线程已完成执行。
*/
TERMINATED;
}
wait/sleep的区别
1、sleep
是Thread
的静态方法, wait
是Object
的方法,任何对象实例都能调用
2、sleep
不会释放锁,它也不需要占用锁。wait
会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized
中)。
3、它们都可以被interrupted
方法中断
并行和并发
并发:同一时刻多个线程在访问同-一个资源,多个线程对一个点
例子:春运抢票电商秒杀…
并行:多项工作- -起执行,之后再汇总
例子:泡方便面,电水壶烧水, -边撕调料倒入桶中。
线程
用户线程:就是自定义线程,主线程结束了,用户线程还在运行,jvm存活
守护线程:比如垃圾回收器,没有用户线程了,都是守护线程,jvm结束
public class Test01 {
public static void main(String[] args) {
Thread test01 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());
while (true) ;
}, "test01");
/*设置守护线程*/
test01.setDaemon(true);
/*启动线程*/
test01.start();
/*主线程*/
System.out.println(Thread.currentThread().getName() + "over");
}
}
Lock接口
Synchronized关键字
synchronized
是Java中的关键字,是一种同步锁。它是修饰对象的有以下几种:
1、修改一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}
括起来的代码,作用的对象是调用这个代码块的对象
2、修饰一个方法;被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;虽然可以使用 synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此, synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了
3、修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象
4、修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象
/**
* @author
* @description
* @date 2022/3/17 19:37
* 1、创建资源类,定义属性和方法
*/
class Ticket {
private int number = 500;
/*验证是否多买了*/
public volatile AtomicInteger atomicInteger = new AtomicInteger(0);
public synchronized void sale() {
if (number > 0) {
atomicInteger.incrementAndGet();
System.out.println(Thread.currentThread().getName() + "卖出一张票,还剩" + number-- + "张票");
}
}
}
public class SaleTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
for (int i = 0; i < 100; i++) {
new Thread(() -> {
for (int i1 = 0; i1 < 10; i1++) {
ticket.sale();
}
}, "aaa" + i).start();
}
while (Thread.activeCount() > 3) ;
System.out.println("完了");
System.out.println(ticket.atomicInteger.get());
}
}
Lock
Lock锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作J它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock提供了比synchronized更多的功能
Lock与的Synchronized区别
Lock不是Java语言内置的, synchronized是Java语言的关键字,因此是内置特性。Lock 是一个类 ,通过这个类可以实现同步访问;。
Lock和synchronized有-点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized 代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
Lock和synchronized有以下几点不同
-
Lock 是一一个接口,而synchronized是Java中的关键字, synchronized是内
置的语言实现:。 -
synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现
象发生;而Lock在发生异常时,如果没有主动通过unLock0
去释放锁,则很
可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;。 -
Lock 可以让等待锁的线程响应中断,而synchronized却不行,使用
synchronized时,等待的线程会一直等待下去 ,不能够响应中断i。
4.通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。。 -
Lock 可以提高多个线程进行读操作的效率。。
-
Lock 可以提高多个线程进行读操作的效率。I
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源
非常激烈时(即有大量线程同时竞争) , 此时Lock的性能要远远优于
class LTicket {
private int number = 300;
private final ReentrantLock lock = new ReentrantLock();
public volatile AtomicInteger atomicInteger = new AtomicInteger(0);
public void sale() {
lock.lock();
try {
if (number > 0) {
atomicInteger.incrementAndGet();
System.out.println(Thread.currentThread().getName() + "卖出一张票,还剩" + number-- + "张票");
}
} finally {
lock.unlock();
}
}
}
public class LSaleTicket {
public static void main(String[] args) {
LTicket ticket = new LTicket();
for (int i = 0; i < 100; i++) {
new Thread(() -> {
for (int i1 = 0; i1 < 10; i1++) {
ticket.sale();
}
}, "aaa" + i).start();
}
while (Thread.activeCount() > 3) ;
System.out.println("完了");
System.out.println(ticket.atomicInteger.get());
}
}
线程间的通信
多线程的编程步骤
1、创建资源类,在资源类中创建属性和操作方法
2、在资源类操作方法
判断、干活、通知
3、创建多个线程,调用资源类的操作方法
4、防止虚假唤醒问题
synchronized版
class Share {
private int number = 0;
public synchronized void increment() {
/*2.1、判断*/
/*防止虚假唤醒 用while*/
while (number != 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*2.2、干活*/
number++;
System.out.println(Thread.currentThread().getName() + "::" + number);
/*2.3、通知*/
this.notifyAll();
}
public synchronized void decrement() {
/*2.1、判断*/
while (number == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*2.2、干活*/
number--;
System.out.println(Thread.currentThread().getName() + "::" + number);
/*2.3、通知*/
this.notifyAll();
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Share share = new Share();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.increment();
}
}, "AAA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.decrement();
}
}, "BBB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.increment();
}
}, "CCC").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.decrement();
}
}, "DDD").start();
}
}
lock版
class Share2 {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment() {
lock.lock();
try {
/*2.1、判断*/
while (number != 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*2.2、干活*/
number++;
System.out.println(Thread.currentThread().getName() + "::" + number);
/*2.3、通知*/
condition.signalAll();
} finally {
lock.unlock();
}
}
public synchronized void decrement() {
lock.lock();
try {
/*2.1、判断*/
while (number == 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*2.2、干活*/
number--;
System.out.println(Thread.currentThread().getName() + "::" + number);
/*2.3、通知*/
condition.signalAll();
} finally {
lock.unlock();
}
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
Share2 share = new Share2();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.increment();
}
}, "AAA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.decrement();
}
}, "BBB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.increment();
}
}, "CCC").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.decrement();
}
}, "DDD").start();
}
}
线程间定制化通信
class Share3 {
private int flag = 0;
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5() {
lock.lock();
try {
/*2.1、判断*/
while (flag != 0) {
try {
c1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*2.2、干活*/
System.out.println(Thread.currentThread().getName() + ":: 打印5次");
flag=1;
/*2.3、通知*/
c2.signal();
} finally {
lock.unlock();
}
}
public void print10() {
lock.lock();
try {
/*2.1、判断*/
while (flag != 1) {
try {
c2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*2.2、干活*/
System.out.println(Thread.currentThread().getName() + ":: 打印10次");
flag=2;
/*2.3、通知*/
c3.signal();
} finally {
lock.unlock();
}
}
public void print15() {
lock.lock();
try {
/*2.1、判断*/
while (flag != 2) {
try {
c3.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/*2.2、干活*/
flag=0;
System.out.println(Thread.currentThread().getName() + ":: 打印15次");
/*2.3、通知*/
c1.signal();
} finally {
lock.unlock();
}
}
}
public class ThreadDemo3 {
public static void main(String[] args) {
Share3 share = new Share3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.print5();
}
}, "AAA").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.print10();
}
}, "BBB").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
share.print15();
}
}, "CCC").start();
System.out.println("线程完成");
}
}
集合的线程安全问题
ArrayList不安全解决方案:
-
使用
Vector
类 -
使用
Collections
工具类-
List<String> strings = Collections.synchronizedList(new ArrayList<>());
-
-
使用
CopyOnWriteArrayList
-
List<String> strings1 = new CopyOnWriteArrayList<>(); strings1.add("sdfasd"); strings1.get(0);
-
HashSet不安全解决方案:
-
CopyOnWriteArraySet
HashMap不安全解决方案:
-
ConcurrentHashMap<String, String> stringStringConcurrentHashMap = new ConcurrentHashMap<>();
多线程锁
8锁
1标准访问,先打印短信还是邮件
2停4秒在短信方法内,先打印短信还是邮件
3新增普通的hello方法,是先打短信还是hello
4现在有两部手机,先打印短信还是邮件
5两个静态同步方法, 1部手机,先打印短信还是邮件
6两个静态同步方法,2部手机,先打印短信还是邮件
7 1个静态同步方法, 1个普通同步方法, 1部手机,先打印短信还是邮件
8 1个静态同步方法, 1个普通同步方法, 2部手机,先打印短信还是邮件
synchronized实现同步的基础: Java中的每一个对象都可以作为锁。
具体表现为以下3种形式。
对于普通同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前类的Class对象。
对于同步方法块,锁是synchonized
括号里配置的对象
class Phone {
public static synchronized void sendSMS() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("SMS");
}
public synchronized void sendEmail() {
System.out.println("email");
}
public void getHello() {
System.out.println("hello");
}
}
public class Thread8Lock {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone.sendSMS();
}, "AA").start();
Thread.sleep(100);
new Thread(() -> {
phone.sendEmail();
// phone.getHello();
}, "AA").start();
}
}
公平锁和非公平锁
非公平锁:线程可能饿死,效率高
公平锁:公平分配,效率较低
可重入锁
synchronized(隐式)和Lock(显式)都是可重入锁 (套娃)
Object o = new Object();
if (true) {
synchronized (o) {
synchronized (o) {
synchronized (o) {
}
}
}
}
死锁
两个或两个以上的线程在执行过程中,因为争夺资源而造成互相等待的现象,
public static void main(String[] args) {
new Thread(() -> {
synchronized (a) {
System.out.println(Thread.currentThread().getName()+"获得a了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName()+"获得b了");
}
}
}).start();
new Thread(() -> {
synchronized (b) {
System.out.println(Thread.currentThread().getName()+"获得b了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println(Thread.currentThread().getName()+"获得a了");
}
}
}).start();
}
验证死锁
1、jps 类似linux 中的 ps -ef
命令行输入jsp -l
C:\Users\Administrator>jps -l
17360 sun.tools.jps.Jps
12628
13268 org.jetbrains.idea.maven.server.RemoteMavenServer36
27748 org.jetbrains.jps.cmdline.Launcher
30100 org.jetbrains.jps.cmdline.Launcher
9108 com.tyred.juc.test.DeadLock
11896 org.jetbrains.idea.maven.server.RemoteMavenServer36
C:\Users\Administrator>jstack 9108
2022-03-18 16:28:29
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.162-b12 mixed mode):
"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x00000000037a4000 nid=0x4228 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #13 prio=5 os_prio=0 tid=0x0000000020aa2000 nid=0x3024 waiting for monitor entry [0x00000000212ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.tyred.juc.test.DeadLock.lambda$main$1(DeadLock.java:37)
- waiting to lock <0x000000076b303ae8> (a java.lang.Object)
- locked <0x000000076b303af8> (a java.lang.Object)
at com.tyred.juc.test.DeadLock$$Lambda$2/885284298.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0" #12 prio=5 os_prio=0 tid=0x0000000020a9b800 nid=0x910 waiting for monitor entry [0x00000000211ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.tyred.juc.test.DeadLock.lambda$main$0(DeadLock.java:24)
- waiting to lock <0x000000076b303af8> (a java.lang.Object)
- locked <0x000000076b303ae8> (a java.lang.Object)
at com.tyred.juc.test.DeadLock$$Lambda$1/2093176254.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001ee9d800 nid=0x433c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000001edf7000 nid=0x7a64 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001edf6800 nid=0xe1c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001edf5800 nid=0x1e1c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001edf3000 nid=0x6504 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001ede7000 nid=0x5cc0 runnable [0x00000000202fe000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x000000076b3cf3d8> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x000000076b3cf3d8> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:49)
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001ecb0800 nid=0x6e6c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001ec5a000 nid=0xc34 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001ec33000 nid=0x2824 in Object.wait() [0x000000001ff9f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076b108ec0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x000000076b108ec0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:212)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000000389c000 nid=0x6b18 in Object.wait() [0x000000001fe9e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076b106b68> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000076b106b68> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=2 tid=0x000000001ec12800 nid=0xf74 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000037b9800 nid=0x4b5c runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000037bb800 nid=0x1b04 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000037bd000 nid=0x558 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000037be800 nid=0x77a0 runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00000000037c1800 nid=0x1fd4 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00000000037c3000 nid=0x2334 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00000000037c6000 nid=0x7ab8 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00000000037c7000 nid=0x4780 runnable
"GC task thread#8 (ParallelGC)" os_prio=0 tid=0x00000000037c8800 nid=0x3378 runnable
"GC task thread#9 (ParallelGC)" os_prio=0 tid=0x00000000037c9800 nid=0x3f50 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x000000001ef4d800 nid=0x6410 waiting on condition
JNI global references: 317
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x000000001d560c98 (object 0x000000076b303ae8, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000000001d563688 (object 0x000000076b303af8, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.tyred.juc.test.DeadLock.lambda$main$1(DeadLock.java:37)
- waiting to lock <0x000000076b303ae8> (a java.lang.Object)
- locked <0x000000076b303af8> (a java.lang.Object)
at com.tyred.juc.test.DeadLock$$Lambda$2/885284298.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at com.tyred.juc.test.DeadLock.lambda$main$0(DeadLock.java:24)
- waiting to lock <0x000000076b303af8> (a java.lang.Object)
- locked <0x000000076b303ae8> (a java.lang.Object)
at com.tyred.juc.test.DeadLock$$Lambda$1/2093176254.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
Found 1 deadlock.
2、jstack jvm中自带的堆栈跟踪工具
Callable接口
创建线程的方式
1、继承Thread类
2、实现Runnable接口
3、实现Callable接口
4、线程池
class MyThread1 implements Runnable {
@Override
public void run() {
}
}
class MyThread2 implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "s2341234";
}
}
public class Demo1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> stringFutureTask = new FutureTask<>(new MyThread2());
new Thread(stringFutureTask).start();
System.out.println(stringFutureTask.get());
System.out.println(stringFutureTask.get());
System.out.println(stringFutureTask.get());
}
}
CountDownLatch
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "走了");
countDownLatch.countDown();
}
}, i + "").start();
}
countDownLatch.await();
System.out.println("wnalel");
}
}
CyclicBrrier
(循环栅栏)
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("完了");
});
for (int i = 0; i < 7; i++) {
new Thread(()->{
System.out.println("得到了"+Thread.currentThread().getName()+"个");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},i+"").start();
}
}
}
Semaphore
信号灯
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 7; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "抢到了位置");
Thread.sleep(new Random().nextInt(5)*1000);
System.out.println(Thread.currentThread().getName() + "走了");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}).start();
}
}
}
读写锁
特点:一个资源可以被多个读线程访问,或者可以被一个写线程访问,但是不能同时存在读写线程,读写互斥,读读共享的
class MyCache {
/**
* 数据集合
*/
private volatile Map<String, Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
/**
* 写数据
*
* @param key
* @param value
*/
public void put(String key, Object value) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "正在写操作" + key);
Thread.sleep(300);
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "写完了" + key);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
/**
* 读数据
*
* @param key
* @return
*/
public Object get(String key) {
Object result = null;
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "正在读操作" + key);
Thread.sleep(300);
result = map.get(key);
System.out.println(Thread.currentThread().getName() + "读完了" + key + ",result=" + result);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
return result;
}
}
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 0; i < 5; i++) {
final int num = i;
new Thread(() -> {
myCache.put(num + "", num + "");
}, "" + num).start();
}
for (int i = 0; i < 5; i++) {
final int num = i;
new Thread(() -> {
myCache.get(num + "");
}, "" + num).start();
}
}
}
synchronized
是JVM
实现的一种锁, 用于同步方法和代码块,执行完后自动释放锁。其中锁的获取和释放分别是monitorenter
和monitorexit
指令,该锁在实现上分为了偏向锁、轻量级锁和重量级锁,其中偏向锁在1.6是默认开启的,轻量级锁在多线程竞争的情况下会膨胀成重量级锁,有关锁的数据都保存在对象头中。
Lock
Lock是一个锁的接口,提供获取锁和解锁的方法(lock,trylock,unlock)
ReentrantLock
ReentrantLock
是k是Lock接口的实现类,基于AQS实现的,在AQS内部会保存一个状态变量state,通过CAS
修改该变量的值,修改成功的线程表示获取到该锁,没有修改成功,或者发现状态state已经是加锁状态,则通过一个Waiter对象封装线程,添加到等待队列中,并挂起等待被唤醒。
ReadWriteLock
可以实现读写锁,当读取的时候线程会获得read锁,其他线程也可以获得read锁同时并发的去读取,但是写程序运行获取到write锁的时候,其他线程是不能进行操作的,因为write是排它锁,而上面介绍的两种不管你是read还是write没有抢到锁的线程都会被阻塞或者中断,它也是个接口,里面定义了两种方法readLock()
和writeLock()
,他的一个实现类是ReentrantReadWriteLock
。
缺点:1、造成锁饥饿,一直读,没有写操作,2、读的时候,不能写,只有读完成之后,才可以写,写操作可以读
1.Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性
2.ReetrantReadWriteLock读写锁的效率明显高于synchronized关键字
3.ReetrantReadWriteLock读写锁的实现中,读锁使用共享模式;写锁使用独占模式,换句话说,读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的
4.ReetrantReadWriteLock读写锁的实现中,需要注意的,当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁
锁降级
将写入锁降级为读锁
public class Demote {
public static void main(String[] args) {
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
/*锁降级 写锁降级为读锁*/
/*1、获取写锁*/
writeLock.lock();
System.out.println("dddd");
/*2、获取读锁*/
readLock.lock();
System.out.println("asdf");
/*3、释放写锁*/
writeLock.unlock();
/*4、释放读锁*/
readLock.unlock();
/*锁降级 读锁不能降级为写锁*/
/*2、获取读锁*/
readLock.lock();
System.out.println("asdf");
/*1、获取写锁*/
writeLock.lock();/*会阻塞*/
System.out.println("dddd");
/*3、释放写锁*/
writeLock.unlock();
/*4、释放读锁*/
readLock.unlock();
}
}
阻塞队列
特点:
当队列是空的,从队列中获取元索的操作将会被阻塞
当队列是满的,从队列中添加元索的操作将会被阻塞
试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往空的队列插入新的元素。
试图向已满的队列中添加新元索的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者完全清空,使队列变得空闲起来并后续新增