Java多线程--synchronized(三)

synchronized(object) 非this对象锁

package ch02.test4;


import java.util.ArrayList;
import java.util.List;

class MyList {
    private List list = new ArrayList();
    public synchronized void add(String data) {
        list.add(data);
    }
    public synchronized int getSize() {
        return list.size();
    }
}

class MyService {
    public MyList addServiceMethod(MyList list, String data) {
        try {
            if(list.getSize() < 1) {
                Thread.sleep(2000);
                list.add(data);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return list;
    }
}

class MyThread1 extends Thread {
    private MyList list;

    public MyThread1(MyList list) {
        this.list = list;
    }

    @Override
    public void run() {
        super.run();
        MyService myService = new MyService();
        myService.addServiceMethod(list,"A");
    }
}

class MyThread2 extends Thread {
    private MyList list;

    public MyThread2(MyList list) {
        this.list = list;
    }

    @Override
    public void run() {
        super.run();
        MyService myService = new MyService();
        myService.addServiceMethod(list,"B");
    }
}

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyList list = new MyList();
        MyThread1 myThread1 = new MyThread1(list);
        myThread1.setName("A");
        myThread1.start();
        MyThread2 myThread2 = new MyThread2(list);
        myThread2.setName("B");
        myThread2.start();
        Thread.sleep(6000);
        System.out.println("listSize="+list.getSize());
    }
}

output:
listSize=2
出现“脏读”的原因是两个线程以异步的方式返回list的大小。
解决方法:
修改MyService类:

class MyService {
    public MyList addServiceMethod(MyList list, String data) {
        try {
            synchronized (list) {
                if (list.getSize() < 1) {
                    Thread.sleep(2000);
                    list.add(data);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return list;
    }
}

修改之后,对同一个list对象,在代码块中,线程A始终保持对list对象的锁,因而线程B在线程A完成add操作之前不能执行list的同步方法。

synchronized静态同步方法和synchronized(class)代码块

  1. synchronized静态同步方法
    synchronized加到static方法是给Class类上锁,而加到非static方法是给对象上锁。
package ch02.test5;



public class Test {
    Service service = new Service();

    public static void main(String[] args) {
        Service service = new Service();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("a");
        threadA.start();
        ThreadB threadB = new ThreadB(service);
        threadB.setName("b");
        threadB.start();
        ThreadC threadC = new ThreadC(service);
        threadC.setName("c");
        threadC.start();
    }
}

class Service {
    synchronized public static void printA() {
        try {
            System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printA");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void printB() {
            System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printB");
            System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printB");
    }
    synchronized public void printC() {
            System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printC");
            System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printC");
    }
}

class ThreadA extends Thread {
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.printA();
    }
}

class ThreadB extends Thread {
    private Service service;

    public ThreadB(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.printB();
    }
}
class ThreadC extends Thread {
    private Service service;

    public ThreadC(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.printC();
    }
}

output:

线程a在1599825585555进入printA
线程c在1599825585564进入printC
线程c在1599825585564离开printC
线程a在1599825588556离开printA
线程b在1599825588556进入printB
线程b在1599825588556离开printB

从结果上来看,线程A和线程B之间是同步的,AC之间以及BC之间是异步的。

原因是线程A和线程B分别持有不同的锁,线程A持有的是Class锁,线程B持有的是对象锁。

posted @ 2020-09-11 21:37  来一块小饼干  阅读(129)  评论(0编辑  收藏  举报