zoukankan      html  css  js  c++  java
  • Java 多线程

    Java 多线程 - synchronize 关键字

    学习自

    http://cmsblogs.com/?p=2071

    https://www.cnblogs.com/xrq730/p/4853713.html

    synchronize 关键字的作用

    synchronize关键字的作用是,使得本来是有操作的多线程在执行某些方法代码段 的时候,变得同步起来。即同一时间内只有一个线程能够访问,而且只有当该线程执行完成同步的代码之后,其他线程才能继续访问。

    使用synchronize
    • 普通的同步方法 , 锁住的是当前类的实例对象this.
    private synchronized void test() {
    }
    
    • 静态同步方法,锁住的是当前类的字节码对象Class
    private synchronized static void test2() {
    }
    
    • 方法内的锁,锁住指定的对象
    private synchronized void test3() {
        synchronized (this) {
            
        }
    }
    

    通过 synchronize 来实现同步

    @Override
    public void call() {
        new Thread(() -> print()).start();
        new Thread(() -> print()).start();
    }
    /**
     * Print
     */
    private synchronized void print() {
        for (int i = 0; i < 10; i++) {
            Thread currentThread = Thread.currentThread();
            System.out.printf("Current thread is %s : print %d 
    ", currentThread.getName(), i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //输出结果
    Current thread is Thread-0 : print 0 
    Current thread is Thread-0 : print 1 
    Current thread is Thread-0 : print 2 
    Current thread is Thread-0 : print 3 
    Current thread is Thread-0 : print 4 
    Current thread is Thread-0 : print 5 
    Current thread is Thread-0 : print 6 
    Current thread is Thread-0 : print 7 
    Current thread is Thread-0 : print 8 
    Current thread is Thread-0 : print 9 
    Current thread is Thread-1 : print 0 
    Current thread is Thread-1 : print 1 
    Current thread is Thread-1 : print 2 
    Current thread is Thread-1 : print 3 
    Current thread is Thread-1 : print 4 
    Current thread is Thread-1 : print 5 
    Current thread is Thread-1 : print 6 
    Current thread is Thread-1 : print 7 
    Current thread is Thread-1 : print 8 
    Current thread is Thread-1 : print 9 
    

    从上面的打印中,我们能够看出来,只有当第一个线程执行完print 方法后第二个线程才会执行。这样的话就实现了线程的同步,在一些比较敏感的操作的时候一定要注意线程的同步,避免出现无法预料的错误。

    死锁

    synchronized 关键字虽然十分的强大,但是如果使用不当就会造成线程的死锁,造成严重的资源浪费。 而且线程死锁的情况,并不是每次都会出现,而是可能会发生死锁,尤其是在高并发的情况下。

    造成死锁的原因

    好,现在让我们回忆一下,西游记中流沙河的一个桥段。

    孙悟空 : 妖怪,你敢上来吗。

    沙悟净 : 你敢下来吗。

    孙悟空 : 妖怪,你敢上来吗。

    沙悟净 : 你敢下来吗。

    .....

    因为孙悟空 占据了陆地,沙悟净 想上陆地,但是上不去,因为打不过啊,而孙悟空想下海擒拿 沙悟净,但是也下不了海,因为沙悟净 占据了海下,再加上 孙猴子 水性不好,所以就一直在僵持着... -_-||。

    上面的这个例子虽然有点生搬硬套的嫌疑,但是,这个例子,很想我们多线程死锁的清苦。

    假设现在有 AB两个锁对象,并且有T1,T2 两个线程,当 T1 占据A对象等在B对象的同时,如果T2占据了B对象等待A对象的时候,因为T1占据了A对象,T1占据了B对象,T1等待B对象,T2等待A对象,但是T1所等在的B对象被T2占据了,而T2等待的A对象被T1所占据。这样相互的等待,就造成了线程的死锁。

    死锁的例子
    Object leftHand = new Object();
    Object rightHand = new Object();
    
    public void call() {
        new Thread(() -> deadLock1()).start();
        new Thread(() -> deadLock2()).start();
    }
    
    /**
     * 多线程的死锁
     */
    private void deadLock1() {
        synchronized (leftHand) {
            //为了创造死锁的条件,让线程睡一会
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (rightHand) {
                System.out.println("Right hand");
            }
        }
    }
    /**
     * 多线程的死锁
     */
    private void deadLock2() {
        synchronized (rightHand) {
            synchronized (leftHand) {
                System.out.println("Left hand");
            }
        }
    }
    

    现在当我们运行程序的时候什么也不会打印出来,因为线程处于了死锁状态。

    避免死锁

    • 注意枷锁的顺序,如果加锁的顺序是相同的,那么是不会发生死锁的。
    • 避免锁的嵌套
    • 通过Lock对象来加锁可以检测到死锁的情况,详细信息可以参考此博客, http://www.cnblogs.com/dolphin0520/p/3923167.html
  • 相关阅读:
    【ThreadLocal】使用ThreadLocal实现线程安全
    【Https】Spring RestTemplete支持Https安全请求
    【MySql】Windows手动注册、启动、数据拷贝
    【技术问题】时空大数据0001---基本知识
    【NodeJS】Vue-d2Admin
    【Oracle】Windows启动
    【三维地质】角点网格
    技术总结
    【Sqlite】C#不同支持
    【Java】Spring
  • 原文地址:https://www.cnblogs.com/slyfox/p/8685709.html
Copyright © 2011-2022 走看看