synchronized的初步使用

前言:这是在慕课网上学习剑指Java面试-Offer直通车时所做的笔记,主要供本人复习之用.

目录

第一章 线程安全问题诱因

第二章 互斥锁

第三章 获取对象锁

3.1 实例代码1

3.2 实例代码2

第四章 类锁

4.1 实例代码1

4.2 实例代码2

4.3 实例代码3

第五章 总结


第一章 线程安全问题诱因

1.存在共享数据(也称临界资源)

2.存在多条线程共同操作这些共享数据

解决问题的根本方法:

第二章 互斥锁

第一章的问题可以用互斥锁解决,而关键字sychronized满足了上述的要求,实现了互斥锁的功能,在线程同步中扮演了非常重要的作用.可以保证在一个时刻只有一个线程可以执行某个方法或者某个代码块,同时synchronized也可以保证一个线程的变化.主要是共享数据的变化,保证这个变化被其它线程锁看到.

synchronized锁的不是代码,锁的都是对象.堆是线程间共享的,是和程序员打交道最多的区域,因此恰当合理的给一个对象上锁,是解决线程安全问题的关键.

根据获取的锁的分类:获取对象锁和获取类锁

第三章 获取对象锁

获取对象锁的两种方法:

1.第一种用法是我们用到的同步代码块,主要通过调用synchronized(this),synchronized(类实例对象),在获取了这些对象的锁之后去执行花括号{}里的内容,锁就是()中的实例对象.

2.第二种是同步非静态方法,即以synchronized修饰符作为前缀的method,锁是当前对象的实例对象.

3.1 实例代码1

public class SyncThread implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        if (threadName.startsWith("A")) {
            async();
        } else if (threadName.startsWith("B")) {
            syncObjectBlock1();
        } else if (threadName.startsWith("C")) {
            syncObjectMethod1();
        } 

    }

    /**
     * 异步方法
     */
    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();
        }
    }
   
}

我们对异步,同步块,同步方法都创建两个线程.然后传入同一个对象锁.注意这里只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");
        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");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
    }
}

输出结果:

B_thread1_SyncObjectBlock1: 19:11:12
A_thread1_Async_Start: 19:11:12
C_thread1_SyncObjectMethod1: 19:11:12
B_thread2_SyncObjectBlock1: 19:11:12
C_thread1_SyncObjectMethod1_Start: 19:11:12
A_thread2_Async_Start: 19:11:12
A_thread1_Async_End: 19:11:13
A_thread2_Async_End: 19:11:13
C_thread1_SyncObjectMethod1_End: 19:11:13
B_thread2_SyncObjectBlock1_Start: 19:11:13
B_thread2_SyncObjectBlock1_End: 19:11:14
B_thread1_SyncObjectBlock1_Start: 19:11:14
B_thread1_SyncObjectBlock1_End: 19:11:15
C_thread2_SyncObjectMethod1: 19:11:15
C_thread2_SyncObjectMethod1_Start: 19:11:15
C_thread2_SyncObjectMethod1_End: 19:11:16

分析:先对相同类别的方法的行为进行分析.

相同类别对比:

对于A:两个线程是异步执行的,因为thread1start了之后并未等待thread2并未等待thread1结束才去执行,而是thread1 start之后,thread2采取start.同时也可以看到A类的thread并未受到其它的使用同步锁的线程的影响,之所以不受同步的影响,是因为A类线程的访问方法并没有同步代码块即没有获取同步锁的需求,也就不会受其它代码块的影响.

对于B:我们发现B类线程是同步的,一个线程在访问对象的代码块时,另外一个访问对象的同步代码块的线程会被阻塞,我们发现是要等一个线程(B2)end后另一个线程(B1)才会start.原因是因为线程需要等待当前对象的SyncThread的同步锁,但是synchronized之外的代码块依然是异步的.

对于C:C类的线程访问的是synchronized的非静态的修饰方法,可以看到C类是全部同步的,C1先start然后end之后再到thread2去start和end.

跨类别对比:

对比B与C:先把synchronized外面的代码排除掉,即只看B与C的start与end,我们看到是C1先start的,除了C1先运行完了,其它的B1,B2,C2是不会先运行的.这也就证明了同步方法(在方法前加synchronized)与同步块(synchronized与this)它们锁的是同一个对象也就是公用的是this对象.


3.2 实例代码2

将3.1的主方法的代码换成如下,SyncThread方法不变.

public class SyncDemo {
    public static void main(String[] args) {
        Thread A_thread1 = new Thread(new SyncThread(), "A_thread1");
        Thread A_thread2 = new Thread(new SyncThread(), "A_thread2");
        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");
        A_thread1.start();
        A_thread2.start();
        B_thread1.start();
        B_thread2.start();
        C_thread1.start();
        C_thread2.start();
    }
}

运行后发现变成了全异步的,也就是说线程访问不同对象的synchronized代码块或者synchronized非静态方法都是异步的,同一个类的不同对象的对象锁是互不干扰的.

A_thread2_Async_Start: 19:46:48
C_thread1_SyncObjectMethod1: 19:46:48
A_thread1_Async_Start: 19:46:48
B_thread1_SyncObjectBlock1: 19:46:48
B_thread2_SyncObjectBlock1: 19:46:48
C_thread2_SyncObjectMethod1: 19:46:48
C_thread1_SyncObjectMethod1_Start: 19:46:48
B_thread1_SyncObjectBlock1_Start: 19:46:48
B_thread2_SyncObjectBlock1_Start: 19:46:48
C_thread2_SyncObjectMethod1_Start: 19:46:48
B_thread1_SyncObjectBlock1_End: 19:46:49
A_thread1_Async_End: 19:46:49
B_thread2_SyncObjectBlock1_End: 19:46:49
C_thread1_SyncObjectMethod1_End: 19:46:49
C_thread2_SyncObjectMethod1_End: 19:46:49
A_thread2_Async_End: 19:46:49

第四章 类锁

它们都是和类相关的,因此我们用的是类锁,类锁实际上是通过对象锁实现的,即类的class的对象锁,每个类只有一个Class对象每个类只有一个类锁.

4.1 实例代码1

public class SyncThread implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        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();
        }
    }

    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();
            }
        }
    }

    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();
        }
    }
}
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");
        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();
        D_thread1.start();
        D_thread2.start();
        E_thread1.start();
        E_thread2.start();
    }
}

运行结果:结论与上面是一致的.这里是按顺序依次执行完E1,D2,D1,E2.执行的是synchronized中的内容.

D_thread1_SyncClassBlock1: 19:54:07
A_thread2_Async_Start: 19:54:07
E_thread1_SyncClassMethod1: 19:54:07
A_thread1_Async_Start: 19:54:07
D_thread2_SyncClassBlock1: 19:54:07
E_thread1_SyncClassMethod1_Start: 19:54:07
A_thread2_Async_End: 19:54:08
A_thread1_Async_End: 19:54:08
E_thread1_SyncClassMethod1_End: 19:54:08
D_thread2_SyncClassBlock1_Start: 19:54:08
D_thread2_SyncClassBlock1_End: 19:54:09
D_thread1_SyncClassBlock1_Start: 19:54:09
D_thread1_SyncClassBlock1_End: 19:54:10
E_thread2_SyncClassMethod1: 19:54:10
E_thread2_SyncClassMethod1_Start: 19:54:10
E_thread2_SyncClassMethod1_End: 19:54:11

4.2 实例代码2

修改4.1主方法中的代码如如下:

public class SyncDemo {
    public static void main(String[] args) {
        Thread A_thread1 = new Thread(new SyncThread(), "A_thread1");
        Thread A_thread2 = new Thread(new SyncThread(), "A_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();
        D_thread1.start();
        D_thread2.start();
        E_thread1.start();
        E_thread2.start();
    }
}

输出如下,可以看到执行为E1,D2,D1,E2,这与3.2的完全异步不同,因为这里用的是类锁.

A_thread2_Async_Start: 19:59:37
E_thread1_SyncClassMethod1: 19:59:37
D_thread1_SyncClassBlock1: 19:59:37
A_thread1_Async_Start: 19:59:37
D_thread2_SyncClassBlock1: 19:59:37
E_thread1_SyncClassMethod1_Start: 19:59:37
A_thread1_Async_End: 19:59:38
E_thread1_SyncClassMethod1_End: 19:59:38
A_thread2_Async_End: 19:59:38
D_thread2_SyncClassBlock1_Start: 19:59:38
D_thread2_SyncClassBlock1_End: 19:59:39
D_thread1_SyncClassBlock1_Start: 19:59:39
D_thread1_SyncClassBlock1_End: 19:59:40
E_thread2_SyncClassMethod1: 19:59:40
E_thread2_SyncClassMethod1_Start: 19:59:40
E_thread2_SyncClassMethod1_End: 19:59:41

4.3 实例代码3

对象锁与类锁之间是互不干扰的,无论传入的是同一个对象还是不同的对象.

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");
        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();
    }
}
public class SyncThread implements Runnable {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        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();
        }
    }

    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();
            }
        }
    }

    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();
        }
    }
}

输出如下,可以看到C2的start与E2的start是一起执行的,所以说互不干扰.

E_thread1_SyncClassMethod1: 20:06:19
D_thread2_SyncClassBlock1: 20:06:19
D_thread1_SyncClassBlock1: 20:06:19
A_thread1_Async_Start: 20:06:19
B_thread1_SyncObjectBlock1: 20:06:19
C_thread1_SyncObjectMethod1: 20:06:19
A_thread2_Async_Start: 20:06:19
B_thread2_SyncObjectBlock1: 20:06:19
E_thread1_SyncClassMethod1_Start: 20:06:19
C_thread1_SyncObjectMethod1_Start: 20:06:19
C_thread1_SyncObjectMethod1_End: 20:06:20
E_thread1_SyncClassMethod1_End: 20:06:20
A_thread1_Async_End: 20:06:20
A_thread2_Async_End: 20:06:20
B_thread2_SyncObjectBlock1_Start: 20:06:20
D_thread1_SyncClassBlock1_Start: 20:06:20
D_thread1_SyncClassBlock1_End: 20:06:21
B_thread2_SyncObjectBlock1_End: 20:06:21
D_thread2_SyncClassBlock1_Start: 20:06:21
B_thread1_SyncObjectBlock1_Start: 20:06:21
B_thread1_SyncObjectBlock1_End: 20:06:22
D_thread2_SyncClassBlock1_End: 20:06:22
C_thread2_SyncObjectMethod1: 20:06:22
E_thread2_SyncClassMethod1: 20:06:22
C_thread2_SyncObjectMethod1_Start: 20:06:22
E_thread2_SyncClassMethod1_Start: 20:06:22
C_thread2_SyncObjectMethod1_End: 20:06:23
E_thread2_SyncClassMethod1_End: 20:06:23

第五章 总结

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章