多线程中sychronized修饰符

2019-08-13  本文已影响0人  叫我胖虎大人

线程安全问题的主要诱因

解决问题的根本方法:
同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再对共享数据进行操作


互斥锁的特性


根据获取的锁的分类


代码示例

SyncThread(线程类)


/**
 * 不同的线程name属性,执行不同的run()方法
 * @author panghu
 */
public class SyncThread implements Runnable {
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        //根据前缀判断执行的run()方法
        if (threadName.startsWith("A")) {
            async();
        } else if (threadName.startsWith("B")) {
            syncObjectBlock1();
        } else if (threadName.startsWith("C")) {
            syncObjectMethod1();
        } else if (threadName.startsWith("D")) {
            syncClassBlock1();
        } else if (threadName.startsWith("E")) {
            syncClassMethod1();
        }
    }

    /**
     * 异步方法,不需要获取锁
     */
    private void async(){
        try{
            System.out.println(Thread.currentThread().getName() + "_Async_Start: "
                    + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "_Async_End: "
                    + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    /**
     * 方法中有 synchronized(this|object) {} 同步代码块
     *
     * 先进入方法,再获取对象锁
     */
    private void syncObjectBlock1(){
        System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1: "
                + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        synchronized (this){
            try{
                System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1_Start: "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1_End: "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }


    /**
     * synchronized 修饰非静态方法
     * 进入方法之前就需要获取对象锁
     */
    private synchronized void syncObjectMethod1() {
        System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1: "
                + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        try {
            System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1_Start: "
                    + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1_End: "
                    + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步代码块(synchronized(类.class))
     */
    private void syncClassBlock1() {
        System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1: "
                + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        synchronized (SyncThread.class) {
            try {
                System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1_Start: "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1_End: "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 同步静态方法(synchronized static method)
     */
    private synchronized static void syncClassMethod1() {
        System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1: "
                + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        try {
            System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1_Start: "
                    + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1_End: "
                    + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

SyncDemo(测试类)

测试样例一

public class SyncDemo {
    public static void main(String... args) {
        SyncThread syncThread = new SyncThread();
        Thread A_thread1 = new Thread(syncThread, "A_thread1");
        Thread A_thread2 = new Thread(syncThread, "A_thread2");
        //B1,B2,C1,C2共用同一个对象
        Thread B_thread1 = new Thread(syncThread, "B_thread1");
        Thread B_thread2 = new Thread(syncThread, "B_thread2");
        Thread C_thread1 = new Thread(syncThread, "C_thread1");
        Thread C_thread2 = new Thread(syncThread, "C_thread2");
//        Thread D_thread1 = new Thread(syncThread, "D_thread1");
//        Thread D_thread2 = new Thread(syncThread, "D_thread2");
//        Thread E_thread1 = new Thread(syncThread, "E_thread1");
//        Thread E_thread2 = new Thread(syncThread, "E_thread2");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
//        D_thread1.start();
//        D_thread2.start();
//        E_thread1.start();
//        E_thread2.start();
    }
}

运行结果

A_thread1_Async_Start: 22:07:38
A_thread2_Async_Start: 22:07:38
C_thread1_SyncObjectMethod1: 22:07:38
B_thread1_SyncObjectBlock1: 22:07:38
B_thread2_SyncObjectBlock1: 22:07:38
C_thread1_SyncObjectMethod1_Start: 22:07:38
A_thread1_Async_End: 22:07:39
A_thread2_Async_End: 22:07:39
C_thread1_SyncObjectMethod1_End: 22:07:39
B_thread2_SyncObjectBlock1_Start: 22:07:39
B_thread2_SyncObjectBlock1_End: 22:07:40
B_thread1_SyncObjectBlock1_Start: 22:07:40
B_thread1_SyncObjectBlock1_End: 22:07:41
C_thread2_SyncObjectMethod1: 22:07:41
C_thread2_SyncObjectMethod1_Start: 22:07:41
C_thread2_SyncObjectMethod1_End: 22:07:42

结论:
线程A1,A2单独运行,不影响其他其他线程的运行,同样的其他线程(B1,B2,C1,C2)同样也不影响它们的单独运行.
当线程(B1,B2,C1,C2)其中一个(假设是C1)线程持有同一对象的对象锁之后,B1,B2,C2需要等C1释放对象锁之后才能进入sychronized修饰的模块


测试样例二
将持有的syncThread对象,改为new SyncThread(),这样每个线程拥有的对象就是不同的

public class SyncDemo {
    public static void main(String... args) {
        SyncThread syncThread = new SyncThread();
        Thread A_thread1 = new Thread(syncThread, "A_thread1");
        Thread A_thread2 = new Thread(syncThread, "A_thread2");
        //B1,B2,C1,C2共用同一个对象
        Thread B_thread1 = new Thread(new SyncThread(), "B_thread1");
        Thread B_thread2 = new Thread(new SyncThread(), "B_thread2");
        Thread C_thread1 = new Thread(new SyncThread(), "C_thread1");
        Thread C_thread2 = new Thread(new SyncThread(), "C_thread2");
//        Thread D_thread1 = new Thread(syncThread, "D_thread1");
//        Thread D_thread2 = new Thread(syncThread, "D_thread2");
//        Thread E_thread1 = new Thread(syncThread, "E_thread1");
//        Thread E_thread2 = new Thread(syncThread, "E_thread2");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
//        D_thread1.start();
//        D_thread2.start();
//        E_thread1.start();
//        E_thread2.start();
    }
}

运行结果:

A_thread2_Async_Start: 22:16:37
C_thread2_SyncObjectMethod1: 22:16:37
C_thread1_SyncObjectMethod1: 22:16:37
C_thread2_SyncObjectMethod1_Start: 22:16:37
A_thread1_Async_Start: 22:16:37
B_thread1_SyncObjectBlock1: 22:16:37
B_thread2_SyncObjectBlock1: 22:16:37
C_thread1_SyncObjectMethod1_Start: 22:16:37
B_thread1_SyncObjectBlock1_Start: 22:16:37
B_thread2_SyncObjectBlock1_Start: 22:16:37
A_thread2_Async_End: 22:16:38
A_thread1_Async_End: 22:16:38
C_thread2_SyncObjectMethod1_End: 22:16:38
C_thread1_SyncObjectMethod1_End: 22:16:38
B_thread2_SyncObjectBlock1_End: 22:16:38
B_thread1_SyncObjectBlock1_End: 22:16:38

结论:线程B1,B2,C1,C2所持有的对象锁不同,互不影响


测试样例三

public class SyncDemo {
    public static void main(String... args) {
        SyncThread syncThread = new SyncThread();
        Thread A_thread1 = new Thread(syncThread, "A_thread1");
        Thread A_thread2 = new Thread(syncThread, "A_thread2");
        //B1,B2,C1,C2共用同一个对象
//        Thread B_thread1 = new Thread(new SyncThread(), "B_thread1");
//        Thread B_thread2 = new Thread(new SyncThread(), "B_thread2");
//        Thread C_thread1 = new Thread(new SyncThread(), "C_thread1");
//        Thread C_thread2 = new Thread(new SyncThread(), "C_thread2");
        Thread D_thread1 = new Thread(syncThread, "D_thread1");
        Thread D_thread2 = new Thread(syncThread, "D_thread2");
        Thread E_thread1 = new Thread(syncThread, "E_thread1");
        Thread E_thread2 = new Thread(syncThread, "E_thread2");
        A_thread1.start();
        A_thread2.start();
//        B_thread1.start();
//        B_thread2.start();
//        C_thread1.start();
//        C_thread2.start();
        D_thread1.start();
        D_thread2.start();
        E_thread1.start();
        E_thread2.start();
    }
}

运行结果:

A_thread1_Async_Start: 22:19:03
D_thread2_SyncClassBlock1: 22:19:03
D_thread1_SyncClassBlock1: 22:19:03
E_thread1_SyncClassMethod1: 22:19:03
A_thread2_Async_Start: 22:19:03
E_thread1_SyncClassMethod1_Start: 22:19:03
A_thread1_Async_End: 22:19:04
A_thread2_Async_End: 22:19:04
E_thread1_SyncClassMethod1_End: 22:19:04
D_thread1_SyncClassBlock1_Start: 22:19:04
D_thread1_SyncClassBlock1_End: 22:19:05
D_thread2_SyncClassBlock1_Start: 22:19:05
D_thread2_SyncClassBlock1_End: 22:19:06
E_thread2_SyncClassMethod1: 22:19:06
E_thread2_SyncClassMethod1_Start: 22:19:06
E_thread2_SyncClassMethod1_End: 22:19:07

结论:当线程(D1,D2,E1,E2)其中一个(假设是E1)线程持有同一对象的对象锁之后,D1,D2,E2需要等E1释放类锁之后才能进入sychronized修饰的模块.


测试样例四

public class SyncDemo {
    public static void main(String... args) {
        SyncThread syncThread = new SyncThread();
        Thread A_thread1 = new Thread(syncThread, "A_thread1");
        Thread A_thread2 = new Thread(syncThread, "A_thread2");
        //B1,B2,C1,C2共用同一个对象
//        Thread B_thread1 = new Thread(new SyncThread(), "B_thread1");
//        Thread B_thread2 = new Thread(new SyncThread(), "B_thread2");
//        Thread C_thread1 = new Thread(new SyncThread(), "C_thread1");
//        Thread C_thread2 = new Thread(new SyncThread(), "C_thread2");
        Thread D_thread1 = new Thread(new SyncThread(), "D_thread1");
        Thread D_thread2 = new Thread(new SyncThread(), "D_thread2");
        Thread E_thread1 = new Thread(new SyncThread(), "E_thread1");
        Thread E_thread2 = new Thread(new SyncThread(), "E_thread2");
        A_thread1.start();
        A_thread2.start();
//        B_thread1.start();
//        B_thread2.start();
//        C_thread1.start();
//        C_thread2.start();
        D_thread1.start();
        D_thread2.start();
        E_thread1.start();
        E_thread2.start();
    }
}

运行结果

A_thread2_Async_Start: 22:23:59
A_thread1_Async_Start: 22:23:59
D_thread1_SyncClassBlock1: 22:23:59
E_thread1_SyncClassMethod1: 22:23:59
D_thread2_SyncClassBlock1: 22:23:59
E_thread1_SyncClassMethod1_Start: 22:23:59
A_thread2_Async_End: 22:24:00
A_thread1_Async_End: 22:24:00
E_thread1_SyncClassMethod1_End: 22:24:00
D_thread2_SyncClassBlock1_Start: 22:24:00
D_thread2_SyncClassBlock1_End: 22:24:01
D_thread1_SyncClassBlock1_Start: 22:24:01
D_thread1_SyncClassBlock1_End: 22:24:02
E_thread2_SyncClassMethod1: 22:24:02
E_thread2_SyncClassMethod1_Start: 22:24:02
E_thread2_SyncClassMethod1_End: 22:24:03

结论:同上述示例3 的结论,将syncThread修改为new SyncThread()获取的依旧是同一个类对象,所以结论相同.

对象锁和类锁的总结

待补充

上一篇下一篇

猜你喜欢

热点阅读