首页 技术 正文
技术 2022年11月15日
0 收藏 839 点赞 3,822 浏览 7948 个字
import java.util.HashMap;import java.util.concurrent.TimeUnit;public class Test {    public static void main(String[] args){//        TickWindowRunnable.test();//        Mutex.test();//        TaskExample.test();//        ThisMonitor.test();        DeadLock.test();    }}/*    4.2 初识synchronized关键字    synchronized关键字可以实现一个简单的策略来防止线程干扰和内存一致性错误,如果一个对象    对多个线程是可见的,那么对该对想的所有读或者写都将通过同步的方式来进行,具体体现如下:        1.synchronized关键字提供了一种锁的机制,能够确保共享变量的互斥访问,从而防止            数据不一致的问题出现。        2.synchronized关键字包括monitor enter和monitor exit两个jvm指令,它能够保证            在任何时候任何线程执行到monitor enter成功之前都必须从主内存中获取数据,而不是            从缓存中,在monitor exit运行成功之后,共享内存被更新后的值必须刷入主内存        3.synchronized的指令严格遵守java happens-before规则,一个monitor exit指令之            前必定要有一个monitor enter *//*    4.2.2 synchronized关键字的用法        1.同步方法:        2.同步代码块:            private final Object MUTEX = new Object();            public void sync(){                synchronized(MUTEX){                    //Do Something...                }            } */class TickWindowRunnable implements Runnable{    private int index = 1;    private final static int MAX = 500;    private final static Object MUTEX = new Object();    @Override    public void run() {        synchronized (MUTEX){            while (index<=MAX){                System.out.println(Thread.currentThread()+"的号码是:"+(index++));            }        }    }    public static void test() {        final TickWindowRunnable task = new TickWindowRunnable();        Thread windowThread1 = new Thread(task,"fir");        Thread windowThread2 = new Thread(task,"sec");        Thread windowThread3 = new Thread(task,"thi");        Thread windowThread4 = new Thread(task,"for");        Thread windowThread5 = new Thread(task,"fif");        windowThread1.start();        windowThread2.start();        windowThread3.start();        windowThread4.start();        windowThread5.start();    }}/*    4.3.1 线程堆栈分析    线程获取了与mutex关联的monitor锁        ——额,一个monitor锁与一个mutex关联着,我这个线程现在进入了你的方法            所以我获取了关联着你这个mutex对象的monitor锁锁锁!!! */class Mutex{    //注意下这个问题,我发现这个对象都是静态的    private final static Object MUTEX = new Object();    public void accessResource(){        synchronized (MUTEX){            try{                TimeUnit.MINUTES.sleep(10);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void test(){        final Mutex mutex = new Mutex();        for (int i = 0; i < 5; i++) {            new Thread(mutex::accessResource).start();        }    }}/*==============================================================================================================================            对 jstack 打印的日志进行分析:=============================================================================================================================="Thread-2" #13 prio=5 os_prio=0 tid=0x000000005696a000 nid=0xe54 waiting for monitor entry [0x000000005812e000]   java.lang.Thread.State: BLOCKED (on object monitor)    at Mutex.accessResource(Test.java:82)    - waiting to lock <0x00000000ec195368> (a java.lang.Object)     //这个地方说明这个线程在等待锁的释放    at Mutex$$Lambda$1/1096979270.run(Unknown Source)    at java.lang.Thread.run(Thread.java:748)"Thread-1" #12 prio=5 os_prio=0 tid=0x0000000056969000 nid=0xc38 waiting on condition [0x000000005825e000]   java.lang.Thread.State: TIMED_WAITING (sleeping)    at java.lang.Thread.sleep(Native Method)    at java.lang.Thread.sleep(Thread.java:340)    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)    at Mutex.accessResource(Test.java:82)    - locked <0x00000000ec195368> (a java.lang.Object)              //这个地方说明这个线程已经获得锁了    at Mutex$$Lambda$1/1096979270.run(Unknown Source)    at java.lang.Thread.run(Thread.java:748)============================================================================================================================== *//*    4.3.2 JVM指令分析==============================================================================================================================            JVM指令分析==============================================================================================================================    public void accessResource();    Code:       0: getstatic     #2       //获取 MUTEX对象       3: dup       4: astore_1       5: monitorenter           //执行monitor enter JVM指令       6: getstatic     #3       9: ldc2_w        #4      12: invokevirtual #6      15: goto          23       //跳转到23行      18: astore_2      19: aload_2      20: invokevirtual #8      23: aload_1                //      24: monitorexit            //执行monitor exit JVM指令      25: goto          33      28: astore_3      29: aload_1      30: monitorexit      31: aload_3      32: athrow      33: return============================================================================================================================== *//*    Monitorenter JVM指令        每个对象都与一个monitor相关联,一个monitor的lock锁只能被一个线程在同一时间获得,        在一个线程尝试获得与对象关联monitor的所有权会发生如下几件事情:            1.如果monitor的计数器为0,则意味这该monitor的lock还没有被获得,某个线程获得                之后将立即对计数器加一,从此该线程就是这个monitor的所有者了。            2.如果一个已经拥有该monitor所有权的线程重入,会导致monitor计数器再次累加。            3.如果monitor已经被其他线程所拥有,则其他线程尝试获取该monitor的所有权时,                或被陷入阻塞状态,知道monitor计数器变为0,才能再次尝试获取对monitor                的所有权。    Monitorexit JVM指令        当monitor计数器变为0时,被该monitor阻塞的线程将再次尝试获得对该monitor的所有权。 *//*    4.3.3 使用synchronized需要注意的问题        1.与monitor关联的对象不能为空        2.synchronized作用域太大了        3.不同的monitor企图锁相同的方法 */class Task implements Runnable{    private final Object MUTEX = new Object();    @Override    public void run() {        synchronized (MUTEX){        }    }}class TaskExample{    public static void test(){        /*            案例解析:                这个案例中构造了5个Runnable实例,Runnable作为线程逻辑执行单元传递给                Thread~~~线程之间进行monitor lock的争夺只能发生在与monitor关联的                同一个引用上!!!所以这个地方,需要new 出一个Task对象,或者将MUTEX                对象编程静态的,但是那没有意义咯,因为你保护的资源大家都有自己的一份,                哈哈哈哈哈哈哈         */        for (int i = 0; i < 5; i++) {            new Thread(Task::new).start();        }    }}/*        4.多个锁的交叉导致死锁            案例分析:                如果write方法和read方法,同时在两个线程中调用,而调用了read方法的线程获                得了MUTEX_READ对象上的monitor锁,调用write方法的线程获得了MUTEX_WRITE                对象上的monitor锁,就会发生死锁。 */class Mutex2{    private final Object MUTEX_READ = new Object();    private final Object MUTEX_WRITE = new Object();    public void read(){        synchronized (MUTEX_READ){            synchronized (MUTEX_WRITE){            }        }    }    public void write() {        synchronized (MUTEX_WRITE){            synchronized (MUTEX_READ){            }        }    }}/*    4.4.1 this monitor */class ThisMonitor{    public synchronized void Method1(){        System.out.println(Thread.currentThread().getName()+" enter to method1");        try{            TimeUnit.MINUTES.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    public synchronized void Method2(){        System.out.println(Thread.currentThread().getName()+" enter to method2");        try{            TimeUnit.MINUTES.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    public static void test(){        ThisMonitor thisMonitor = new ThisMonitor();        new Thread(thisMonitor::Method1,"T1").start();        new Thread(thisMonitor::Method2,"T2").start();    }}/*==============================================================================================================            jstack 打印的日志分析=============================================================================================================="T2" #12 prio=5 os_prio=0 tid=0x0000000057971800 nid=0xb50 waiting for monitor entry [0x000000005837f000]   java.lang.Thread.State: BLOCKED (on object monitor)    at ThisMonitor.Method2(Test.java:251)    - waiting to lock <0x00000000eb3c02b8> (a ThisMonitor)    at ThisMonitor$$Lambda$2/1831932724.run(Unknown Source)    at java.lang.Thread.run(Thread.java:748)"T1" #11 prio=5 os_prio=0 tid=0x000000005796e800 nid=0x16d8 waiting on condition [0x000000005824e000]   java.lang.Thread.State: TIMED_WAITING (sleeping)    at java.lang.Thread.sleep(Native Method)    at java.lang.Thread.sleep(Thread.java:340)    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)    at ThisMonitor.Method1(Test.java:245)    - locked <0x00000000eb3c02b8> (a ThisMonitor)    at ThisMonitor$$Lambda$1/1096979270.run(Unknown Source)    at java.lang.Thread.run(Thread.java:748)==============================================================================================================    自己的分析:        1.我看到了T1进行了加锁,T2在等待锁        2.额,这个类似与什么情况类似?这个类似与我准备了一个MUTEX对象,用它来保护两个语句块            按照我之前看到的,一点需要进入到这个对象保护的区域了,它都需要需询问一下monitor            能否给个锁。但是发现不能狗获得这个锁。所以就只有一个方法运行了。 *//*    4.5.1 程序死锁        1.交叉锁可导致程序出现死锁        2.内存不足导致的死锁        3.一问一答的数据交换        4.数据库锁        5.文件锁        6.死循环引起的死锁    4.5.2 程序死锁举例 */class DeadLock{    private final Object MUTEX_READ = new Object();    private final Object MUTEX_WRITE = new Object();    public void read(){        synchronized (MUTEX_READ){            synchronized (MUTEX_WRITE){                System.out.println("read...");            }        }    }    public void write() {        synchronized (MUTEX_WRITE){            synchronized (MUTEX_READ){                System.out.println("write...");            }        }    }    public static void test() {        final DeadLock deadLock = new DeadLock();        new Thread(()->{            while(true){                deadLock.read();            }        },"READ-THEAD").start();        new Thread(()->{            while(true){                deadLock.write();            }        },"Write-THEAD").start();    }}/*    HashMap 不具备线程安全的能力,如果想要使用线程安全的map结构请使用    ConcurrentHashMap或者使用Collection.synchronizeMap来代替        ——这个还是了解一下吧。。。    案例分析:        书中是这么说的:如果多线程同时写操作的情况下,很容易出现死循环引起的死锁,        程序运行一段时间后,CPU等资源居高不下。            ——我想知道为什么会这样。。。 */class HashMapDeadLock{    private final HashMap<String,String> map = new HashMap<>();    public void add(String key, String value) {        this.map.put(key,value);    }    public static void test(){        final HashMapDeadLock hmdl = new HashMapDeadLock();        for (int x = 0; x < 2; x++) {            new Thread(()->{                for (int i = 1; i < Integer.MAX_VALUE; i++) {                    hmdl.add(String.valueOf(i),String.valueOf(i));                }            }).start();        }    }}/*    4.5.3 死锁诊断        ——这部分没看着,想找本专业的书,看看这部分 */

——《Java高并发编程详解》笔记

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,104
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,580
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,428
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,835
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,918