黑马-并发编程学习
作者:互联网
1、查看 进程 杀死进程
ps -fe | grep java
或者使用jps
top -H -p pid 查看pid代表的进程的内部线程运行情况
使用jstack 也可以查看进程的线程信息 使用方式是jstack pid
使用jconsole 也可以查看某个进程的线程信息 (图形化界面)
2、线程切换的原因
时间片用完
更高级别的线程执行
stw 回收线程执行
线程本身调用 sleep wait join park sychronized 等
3、对象头
Mark Word + klass Word + 对齐填充
轻量级锁的加锁 锁重入 解锁
synchronized(obj) 轻量级锁加锁时需要在加锁线程的栈帧中插入锁记录Lock Record(Mark Word + Object Reference),并通过cas设置 obj 对象头Mark Word 为指向锁记录的指针。cas成功则加锁成功,如果未成功则判断是否本线程之前加过锁,如果是则同样插入一个Lock record 不过Lock Record中的Mark Word不再是复制之前的Mark Word 而是null值,代表计数。如果 之前本线程未加锁 则代表其他线程占有锁了,这时候就发生了争用,需要进行锁升级。解锁过程需要通过cas将LockRecord 中的MarkWord 设置回obj的Mark Word。
轻量级锁膨胀的过程
当加轻量级锁 cas设置失败的时候 就会发生锁膨胀,会为obj 创建对应的监视器Monitor,同时将owner设置为已经运行的线程(轻量锁),并将线程阻塞在EntryList中,处于阻塞状态。之后轻量级锁线程运行临界区之后释放锁时首先会按照轻量级锁的方式释放,即将obj的Markword通过cas设置栈帧中LockRecord中的MarkWord,显然会失败,这是就会尝试重量级锁的释放流程,即通过object reference 获取到obj,obj的MarkWord中目前是重量级锁的指针,所以通过设置Monitor的owner为null,并且唤醒EntryList中的阻塞线程。
轻量级锁 是优化 自旋也是优化
当发现锁对象已经被一个线程占有,那么另一个线程尝试获取锁的时候可以自旋一定次数等待。优势是在锁占有时间短的情况下避免的线程切换的开销,缺点是锁的占有时间过长可能会造成大量线程的自旋等待cpu空转。 适应性自旋指的是根据经验值来判断自旋的时间,比如之前线程在该锁对象的自旋时间和锁的状态决定。
- 偏向锁当只有一个线程一直访问临界区,那么就会将obj 的MarkWord 设置偏向线程id .但是当调用obj的hashcode方法后,会自动禁用偏向锁。因为生成的hashcode 码需要放到对象头的MarkWord中,放不下线程id了。那么你可能有疑问 为什么轻量级锁或者重量级锁不会有这样的问题,这是因为轻量级锁又锁记录来保存对象头,重量级锁有Monitor对象保存。
wait /notify机制
public class Main {
public static void main(String[] args) throws IllegalAccessException {
Package p = new Package(0);
for(int i = 0;i < 3;i++){
new Thread(()->{
try {
while(true){
p.produce();
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
for(int i = 0;i < 3;i++){
new Thread(()->{
try {
while(true){
p.consume();
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
static class Package{
private int count;
private Object Lock = new Object();
public Package(int count) {
this.count = count;
}
public void consume() throws InterruptedException {
synchronized (Lock){
while(count == 0){
Lock.wait();
}
count--;
System.out.println("消费者消费1,目前为"+count);
Lock.notifyAll();
}
}
public void produce() throws InterruptedException {
synchronized (Lock){
while(count == 10){
Lock.wait();
}
count++;
System.out.println("生产者生产1,目前为"+count);
Lock.notifyAll();
}
}
}
}
park unpark 与wait notify 的区别
1、wait notify 必须与Monitor 配合使用
2、 park unpark 作用单位是线程,即使某一个线程等待或者唤醒某一个具体的线程 wait notify 会随机唤醒Monitor 的waitset中的线程。而park unpark 会唤醒具体的某个线程
3、线程只有调用wait ,notify才会起作用将wait的线程唤醒 而park unpark 可以先unpark(thread) 再 park 同样会使得park的线程立即恢复运行。
park unpark 原理
线程转换
死锁的检测工具
jps
D:\worksapce\LeetCode\src\main\java\com\gaojl>jps
17344 Main
22496 RemoteMavenServer36
46672
65600 JConsole
40676 Launcher
16456 Jps
D:\worksapce\LeetCode\src\main\java\com\gaojl>jstack 17344
2021-09-09 09:25:18
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):
"RMI TCP Connection(5)-169.254.116.19" #23 daemon prio=5 os_prio=0 tid=0x000000001f40a800 nid=0x2734 in Object.wait() [0x00000000209ec000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076f680f10> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)
at com.sun.jmx.remote.internal.ArrayNotificationBuffer.fetchNotifications(ArrayNotificationBuffer.java:449)
- locked <0x000000076f680f10> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)
at com.sun.jmx.remote.internal.ArrayNotificationBuffer$ShareBuffer.fetchNotifications(ArrayNotificationBuffer.java:227)
at com.sun.jmx.remote.internal.ServerNotifForwarder.fetchNotifs(ServerNotifForwarder.java:274)
at javax.management.remote.rmi.RMIConnectionImpl$4.run(RMIConnectionImpl.java:1270)
at javax.management.remote.rmi.RMIConnectionImpl$4.run(RMIConnectionImpl.java:1268)
at javax.management.remote.rmi.RMIConnectionImpl.fetchNotifications(RMIConnectionImpl.java:1274)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$5/951671104.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"RMI TCP Connection(4)-169.254.116.19" #22 daemon prio=5 os_prio=0 tid=0x000000001f406000 nid=0xa61c runnable [0x00000000208ed000]
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 java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x000000076f68a268> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$5/951671104.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"RMI TCP Connection(3)-169.254.116.19" #21 daemon prio=5 os_prio=0 tid=0x000000001f4e9000 nid=0x16a4 runnable [0x00000000207ee000]
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 java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x000000076f690df0> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$5/951671104.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"JMX server connection timeout 19" #19 daemon prio=5 os_prio=0 tid=0x000000001f542000 nid=0x5f94 in Object.wait() [0x00000000204ef000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076f698178> (a [I)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
- locked <0x000000076f698178> (a [I)
at java.lang.Thread.run(Thread.java:748)
"RMI Scheduler(0)" #18 daemon prio=5 os_prio=0 tid=0x000000001f52d000 nid=0x2910 waiting on condition [0x00000000203ef000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076f6a0188> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"RMI TCP Accept-0" #16 daemon prio=5 os_prio=0 tid=0x000000001e639800 nid=0xca8c runnable [0x000000001fe7e000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x000000076f6a82b0> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:405)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:377)
at java.lang.Thread.run(Thread.java:748)
"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x0000000002af3800 nid=0xbe58 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"b" #13 prio=5 os_prio=0 tid=0x000000001f3d2800 nid=0x3890 waiting for monitor entry [0x000000001fd2e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.gaojl.Main.lambda$main$1(Main.java:37)
- waiting to lock <0x000000076f6b02f0> (a java.lang.Object)
- locked <0x000000076f6b0300> (a java.lang.Object)
at com.gaojl.Main$$Lambda$2/999966131.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"a" #12 prio=5 os_prio=0 tid=0x000000001f3cf800 nid=0x373c waiting for monitor entry [0x000000001fc2f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.gaojl.Main.lambda$main$0(Main.java:29)
- waiting to lock <0x000000076f6b0300> (a java.lang.Object)
- locked <0x000000076f6b02f0> (a java.lang.Object)
at com.gaojl.Main$$Lambda$1/2093631819.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001e532800 nid=0x47fc runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000001e49a000 nid=0x5288 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001e43c000 nid=0x59fc waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001e439800 nid=0xf61c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001e483000 nid=0x4410 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001e3cc000 nid=0x66f8 runnable [0x000000001ed2e000]
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 <0x000000076f6b8318> (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 <0x000000076f6b8318> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001e3b5000 nid=0xaa94 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001e3b1000 nid=0x12e78 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001e3a1800 nid=0x3f54 in Object.wait() [0x000000001e97f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076f6b0798> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x000000076f6b0798> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001e3a0800 nid=0x9b54 in Object.wait() [0x000000001e87f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076f6b8308> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000076f6b8308> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=2 tid=0x000000001c5a9800 nid=0xbd08 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002b09000 nid=0x69f8 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002b0a800 nid=0xd7ec runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002b0c000 nid=0xdd1c runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002b0e800 nid=0x28ac runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000002b11000 nid=0x6948 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002b12000 nid=0x6958 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000002b15000 nid=0x11c10 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000002b16800 nid=0x100a0 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x000000001e536800 nid=0xfdb4 waiting on condition
JNI global references: 233
Found one Java-level deadlock:
=============================
"b":
waiting to lock monitor 0x0000000002bebc18 (object 0x000000076f6b02f0, a java.lang.Object),
which is held by "a"
"a":
waiting to lock monitor 0x0000000002bee6b8 (object 0x000000076f6b0300, a java.lang.Object),
which is held by "b"
Java stack information for the threads listed above:
===================================================
"b":
at com.gaojl.Main.lambda$main$1(Main.java:37)
- waiting to lock <0x000000076f6b02f0> (a java.lang.Object)
- locked <0x000000076f6b0300> (a java.lang.Object)
at com.gaojl.Main$$Lambda$2/999966131.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"a":
at com.gaojl.Main.lambda$main$0(Main.java:29)
- waiting to lock <0x000000076f6b0300> (a java.lang.Object)
- locked <0x000000076f6b02f0> (a java.lang.Object)
at com.gaojl.Main$$Lambda$1/2093631819.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
reentrantLock 和synchronized
reentrantLock 相比于synchronized,可以支持公平锁,支持多条df件变量。
synchronized 和reentrantlock都支持可重入。
ReentrantLock lock = new ReentrantLock();
lock.lock();
try{
//临界区
}finally {
lock.unlock();
}
reentrantLock响应中断 lock.lockInterruptbily()
reentrantLock超时获取 lock.tryLock(time);
3个线程交替打印 abc 5次
public class Main {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
WaitNotify wn = new WaitNotify(1,3);
new Thread(()->{
wn.print("a",1);
},"t1").start();
new Thread(()->{
wn.print("b",2);
},"t2").start();
new Thread(()->{
wn.print("c",3);
}).start();
}
}
class WaitNotify{
int printFlag;
int looptimes;
public WaitNotify(int printFlag,int looptimes) {
this.printFlag = printFlag;
this.looptimes = looptimes;
}
public void print(String str,int flag){
for (int i = 0; i < looptimes ; i++) {
synchronized (this){
try{
while(printFlag != flag){
this.wait();
}
System.out.println(str);
printFlag = next(printFlag,looptimes);
this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private int next(int now,int limit) {
if(now + 1 <= limit){
return now+1;
}else{
return 1;
}
}
}
public class Main {
public static void main(String[] args) {
AwaitSignal as = new AwaitSignal(3);
Condition a = as.newCondition();
Condition b = as.newCondition();
Condition c = as.newCondition();
new Thread(()->{
as.print("a",a,b);
}).start();
new Thread(()->{
as.print("b",b,c);
}).start();
new Thread(()->{
as.print("c",c,a);
}).start();
as.lock();
try{
a.signal();
}finally {
as.unlock();
}
}
}
class AwaitSignal extends ReentrantLock{
private int looptimes;
public AwaitSignal(int looptimes){
this.looptimes = looptimes;
}
public void print(String str,Condition cur,Condition next){
for (int i = 0; i < looptimes; i++) {
lock();
try{
cur.await();
System.out.print(str);
next.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
unlock();
}
}
}
}
指令重排 优化
指令重排是指在程序执行过程中, 为了性能考虑, 编译器和CPU可能会对指令重新排序
cpu 级别的指令重排优化(取指 分析 执行),每条指令都是经过多个子任务完成,如果按照一条指令执行完再执行另外一条指令,那么需要的时钟周期会很长。假设一条指令要3个时钟周期那么俩条指令就需要6个。其实在取指部件在执行完取值指令后就会空闲下来,这时候就可以执行第二条指令的取指操作了 这时候多条指令达到了并行的效果。指令重排是对于没有依赖关系的俩条指令的,比如a = 1,b = 2 c = a + b 那么 a = 1 和 b=2 是无依赖关系的可以重排。
在DCL单例模式下 Single 是被volatile修饰的 加入不被volatile修饰 那么 single = new Single()过程 其实可以分为 加载 链接 初始化 这里的初始化指的是类构造方法的执行,会将类变量的值设置为默认值。 之后会调用构造方法初始化。 构造方法初始化之后会赋值给 变量。发生指令重排后 会将一个未初始化好的对象给其他线程使用,那么当其他线程使用未初始化好的对象就会出现错误。
Class Single{
private volatile static Single single;
private Single(){}
public static Single getInstance(){
if(single == null){
synchronized(Single.class){
if(single == null){
single = new Single();
return single;
}
}
}
return single
}
}
读写屏障 读指令之前加读屏障 可以保证读屏障之后的读指令不会被编译器优化到读屏障之前。
写屏障 写指令之后的写屏障 可以保证写屏障之前的写指令不会被优化到写屏障之后。
happens-before 原则
happens-before 定义了 共享变量的写操作对其他线程读的可见性。比如先运行的线程对共享变量的修改会对其他线程的读可见
cas 与volatile
cas 设置底层使用的指令是cmpexchg .他需要变量期望的值与主存中的值比较。所以需要将volatile 与cas配合使用。
cas 相比于synchronized的原因,cas 基于乐观锁的思想,失败重试,不会像synchronized那样使得线程阻塞在监视器的entryList上,cas无锁并发 无阻塞并发。但是如果重试次数过多必然会影响效率,所以适合线程数较少 cpu核数较多的情况
final 原理
非 final 变量的 初始化 会分为 clinit 阶段 和 init阶段。所以会存在其他线程拿到未初始化变量的情况。而final变量会在初始化之后直接赋值并在之后加入写屏障。从而让其他线程拿到最新值。
自定义线程池
public class Main {
public static void main(String[] args) {
ThreadPool tp = new ThreadPool(2,TimeUnit.MILLISECONDS,1000,1,((taskQueue, task) -> {
//throw new RuntimeException("阻塞队列满"); 抛出异常
taskQueue.offer(task,1000,TimeUnit.MILLISECONDS);
}));
for(int i = 0;i < 5;i++){
int j = i;
tp.execute(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task"+j);
});
}
}
@FunctionalInterface
interface RejectPolicy<T> {
void reject(BlockingQueue<T> taskQueue, T task);
}
class Person {
Integer id;
String name;
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
}
static class ThreadPool {
private BlockingQueue<Runnable> taskQueue;
HashSet<Worker> workers = new HashSet();
private int coreSize;
private TimeUnit timeUnit;
private long timeout;
private RejectPolicy<Runnable> rejectPolicy;
public ThreadPool(int coreSize, TimeUnit timeUnit, long timeout, int queueCapacity, RejectPolicy<Runnable> rejectPolicy) {
this.coreSize = coreSize;
this.timeUnit = timeUnit;
this.timeout = timeout;
this.taskQueue = new BlockingQueue<>(queueCapacity);
this.rejectPolicy = rejectPolicy;
}
public void execute(Runnable task) {
Worker worker = null;
synchronized (workers) {
if (workers.size() < coreSize) {
worker = new Worker(task);
System.out.println("创建工作线程"+worker);
workers.add(worker);
System.out.println("工作线程"+worker+"执行任务");
worker.start();
} else {
//将任务放入阻塞队列
// taskQueue.put(task);
rejectPolicy.reject(taskQueue,task);
}
}
}
class Worker extends Thread {
private Runnable task;
public Worker(Runnable task) {
this.task = task;
}
@Override
public void run() {
while (task != null || (task = taskQueue.poll(timeout,timeUnit)) != null) {
try {
try {
task.run();
} catch (Exception e) {
}
} finally {
task = null;
}
}
synchronized (workers) {
System.out.println("remove");
workers.remove(this);
}
}
}
}
static class BlockingQueue<T> {
private Deque<T> queue = new ArrayDeque<>();
private Integer capacity;
public BlockingQueue(Integer capacity) {
this.capacity = capacity;
}
private ReentrantLock lock = new ReentrantLock();
private Condition full = lock.newCondition();
private Condition empty = lock.newCondition();
//阻塞获取任务
public T take() {
lock.lock();
try {
while (queue.isEmpty()) {
empty.await();
}
T t = queue.removeFirst();
full.signal();
return t;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return null;
}
public T poll(long timeOut, TimeUnit timeUnit) {
lock.lock();
try {
long nanos = timeUnit.toNanos(timeOut);
while (queue.isEmpty()) {
if(nanos <= 0){
return null;
}
nanos = empty.awaitNanos(nanos);
}
T t = queue.removeFirst();
full.signal();
return t;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return null;
}
public void put(T t) {
lock.lock();
try {
while (queue.size() == capacity) {
try {
full.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.offerLast(t);
empty.signal();
} finally {
lock.unlock();
}
}
public boolean offer(T task, long timeOut, TimeUnit timeUnit) {
lock.lock();
long nanos = timeUnit.toNanos(timeOut);
try {
while (queue.size() >= capacity) {
if (nanos <= 0) {
System.out.println("任务加入队列失败"+task);
return false;
}
nanos = full.awaitNanos(nanos);
}
queue.addLast(task);
empty.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return true;
}
}
}
线程池线程数
cpu 密集型 :cpu 核数+1
io密集型:cpu 核数 X cpu利用率 X (等待时间 + cpu运行时间)/cpu 运行时间
标签:lang,java,prio,Thread,编程,并发,线程,run,黑马 来源: https://blog.csdn.net/mmmmhello/article/details/120131586