黑马-并发编程学习

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 运行时间

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java并发编程 背景介绍 并发历史 必要性 进程 资源分配的最小单位 线程 CPU调度的最小单位 线程的优势 (1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 (2)建模简单:通过使用线程可以讲复杂并且异步的工作流进一步分解成一组简单并且同步的工作流,每个工作流在一个单独的线程中运行,并在特定的同步位置交互 (3)简化异步事件的处理:服务器应用程序在接受来自多个远程客户端的请求时,如果为每个连接都分配一个线程并且使用同步IO,就会降低开发难度 (4)用户界面具备更短的响应时间:现代GUI框架中大都使用一个事件分发线程(类似于中断响应函数)来替代主事件循环,当用户界面用有事件发生时,在事件线程中将调用对应的事件处理函数(类似于中断处理函数) 线程的风险 线程安全性:永远不发生糟糕的事情 活跃性问题:某件正确的事情迟早会发生 问题:希望正确的事情尽快发生 服务时间过长 响应不灵敏 吞吐率过低 资源消耗过高 可伸缩性较低 线程的应用场景 Timer 确保TimerTask访问的对象本身是线程安全的 Servlet和JSP Servlet本身要是线程安全的 正确协同一个Servlet访问多个Servlet共享的信息 远程方法调用(RMI) 正确协同多个对象中的共享状态 正确协同远程对象本身状态的访问 Swing和AWT 事件处理器与访问共享状态的其他代码都要采取线程安全的方式实现 框架通过在框架线程中调用应用程序代码将并发性引入应用程序,因此对线程安全的需求在整个应用程序中都需要考虑 基础知识 线程安全性 定义 当多个线程访问某个类时,这个类始终能表现出正确的行为,那么就称这个类是线程安全的 无状态对象一定是线程安全的,大多数Servlet都是无状态的 原子性 一组不可分割的操作 竞态条件 基于一种可能失效的观察结果来做出判断或执行某个计算 复合操作:执行复合操作期间,要持有锁 锁的作用 加锁机制、用锁保护状态、实现共享访问 锁的不恰当使用可能会引起程序性能下降 对象的共享使用策略 线程封闭:线程封闭的对象只能由一个线程拥有并修改 Ad-hoc线程封闭 栈封闭 ThreadLocal类 只读共享:不变对象一定是线程安全的 尽量将域声明为final类型,除非它们必须是可变的 分类 不可变对象 事实不可变对象 线程安全共享 封装有助于管理复杂度 线程安全的对象在其内部实现同步,因此多个接口可以通过公有接口来进行访问 保护对象:被保护的对象只能通过特定的锁来访问 将对象封装到线程安全对象中 由特定锁保护 保护对象的方法 对象的组合 设计线程安全的类 实例封闭 线程安全的委托 委托是创建线程安全类的最有效策略,只需要让现有的线程安全类管理所有的状态 在现有线程安全类中添加功能 将同步策略文档化 基础构建模块 同步容器类 分类 Vector Hashtable 实现线程安全的方式 将状态封装起来,对每个公有方法都进行同步 存在的问题 复合操作 修正方式 客户端加锁 迭代器 并发容器 ConcurrentHashMap 用于替代同步且基于散列的Map CopyOnWriteArrayList 用于在遍历操作为主要操作的情况下替代同步的List Queue ConcurrentLinkedQueue *BlockingQueue 提供了可阻塞的put和take方法 生产者-消费者模式 中断的处理策略 传递InterruptedException 恢复中断,让更高层的代码处理 PriorityQueue(非并发) ConcurrentSkipListMap 替代同步的SortedMap ConcurrentSkipListSet 替代同步的SortedSet Java 5 Java 6 同步工具类 闭锁 *应用场景 (1)确保某个计算在其需要的所有资源都被初始化后才能继续执行 (2)确保某个服务在其所依赖的所有其他服务都已经启动之后才启动 (3)等待知道某个操作的所有参与者都就绪再继续执行 CountDownLatch:可以使一个或多个线程等待一组事件发生 FutureTask *应用场景 (1)用作异步任务使用,且可以使用get方法获取任务的结果 (2)用于表示一些时间较长的计算 状态 等待运行 正在运行 运行完成 使用Callable对象实例化FutureTask类 信号量(Semaphore) 用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量 管理者一组虚拟的许可。acquire获得许可(相当于P操作),release释放许可(相当于V操作) 应用场景 (1)二值信号量可用作互斥体(mutex) (2)实现资源池,例如数据库连接池 (3)使用信号量将任何一种容器变成有界阻塞容器 栅栏 能够阻塞一组线程直到某个事件发生 栅栏和闭锁的区别 所有线程必须同时到达栅栏位置,才能继续执行 闭锁用于等待事件,而栅栏用于等待线程 栅栏可以重用 形式 CyclicBarrier 可以让一定数量的参与线程反复地在栅栏位置汇集 应用场景在并行迭代算法中非常有用 Exchanger 这是一种两方栅栏,各方在栅栏位置上交换数据。 应用场景:当两方执行不对称的操作(读和取) 线程池 任务与执行策略之间的隐形耦合 线程饥饿死锁 运行时间较长的任务 设置线程池的大小 配置ThreadPoolExecutor 构造参数 corePoolSize 核心线程数大小,当线程数= corePoolSize的时候,会把runnable放入workQueue中 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了” keepAliveTime 保持存活时间,当线程数大于corePoolSize的空闲线程能保持的最大时间。 workQueue 保存任务的阻塞队列 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务 threadFactory 创建线程的工厂 handler 拒绝策略 unit 是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值 线程的创建与销毁 管理队列任务 饱和策略 AbortPolicy DiscardPolicy DiscardOldestPolicy CallerRunsPolicy 线程工厂 在调用构造函数后再定制ThreadPoolExecutor 扩展 ThreadPoolExecutor afterExecute(Runnable r, Throwable t) beforeExecute(Thread t, Runnable r) terminated 递归算法的并行化 构建并发应用程序 任务执行 在线程中执行任务 清晰的任务边界以及明确的任务执行策略 任务边界 大多数服务器以独立的客户请求为界 在每个请求中还可以发现可并行的部分 任务执行策略 在什么(What)线程中执行任务? 任务按照什么(What)顺序执行(FIFO、LIFO、优先级)? 有多少个(How Many)任务能并发执行? 在队列中有多少个(How Many)任务在等待执行? 如果系统由于过载而需要拒绝一个任务,那么应该选择哪一个(Which)任务?另外,如何(How)通知应用程序有任务被拒绝? 在执行一个任务之前或之后,应该进行什么(What)动作? 使用Exector框架 线程池 newFixedThreadPool(固定长度的线程池) newCachedThreadPool(不限规模的线程池) newSingleThreadPool(单线程线程池) newScheduledThreadPool(带延迟/定时的固定长度线程池) 具体如何使用可以查看JDK文档 找出可利用的并行性 某些应用程序中存在比较明显的任务边界,而在其他一些程序中则需要进一步分析才能揭示出粒度更细的并行性 任务的取消和关闭 任务取消 停止基于线程的服务 处理非正常的线程终止 JVM关闭 线程池的定制化使用 任务和执行策略之间的隐性耦合 线程池的大小 配置ThreadPoolExecutor(自定义的线程池) 此处需要注意系统默认提供的线程池是如何配置的 扩展ThreadPoolExector GUI应用程序探讨 活跃度(Liveness)、性能、测试 避免活跃性危险 死锁 锁顺序死锁 资源死锁 动态的锁顺序死锁 开放调用 在协作对象之间发生的死锁 死锁的避免与诊断 支持定时的显示锁 通过线程转储信息来分析死锁 其他活跃性危险 饥饿 要避免使用线程优先级,因为这会增加平台依赖性,并可能导致活跃性问题。在大多数并发应用程序中,都可以使用默认的线程优先级。 糟糕的响应性 如果由其他线程完成的工作都是后台任务,那么应该降低它们的优先级,从而提高前台程序的响应性。 活锁 要解决这种活锁问题,需要在重试机制中引入随机性(randomness)。为了避免这种情况发生,需要让它们分别等待一段随机的时间 性能与可伸缩性 概念 运行速度(服务时间、延时) 处理能力(吞吐量、计算容量) 可伸缩性:当增加计算资源时,程序的处理能力变强 如何提升可伸缩性 Java并发程序中的串行,主要来自独占的资源锁 优化策略 缩
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值