在java中处理线程并发问题,可以简单的加上synchronized,可以在方法或方法内的代码块添加,那现在的问题是,synchronized是锁住了方法还是代码块还是实例对象?
加在方法上:

class Sync {
    public synchronized void test() {
        System.out.println("test开始..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test结束..");
    }
}

class MyThread extends Thread {
    public void run() {
        Sync sync = new Sync();
        sync.test();
    }
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            Thread thread = new MyThread();
            thread.start();
        }
    }
}

运行结果: test开始.. test开始.. test开始.. test结束.. test结束.. test结束
可以看到,上面启了3个线程,每个线程实例化一个Sync并调用其方法,所以这里synchronized没有作用,因为线程都加了各自的同步锁,无互斥。

若把test方法上加上static,则运行结果如下:
test开始.. test结束.. test开始.. test结束.. test开始.. test结束
因为此时,3个线程的同步锁是Sync类对象而不是类实例。

public static synchronized void test() {
        System.out.println("test开始..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test结束..");
    }

注:线程sleep时,并不会释放锁.

接下来,把synchronized加到this上,如下:

public void test() {
     synchronized(this) {
        System.out.println("test开始..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test结束..");
    }
}

运行结果:test开始.. test开始.. test开始.. test结束.. test结束.. test结束
同样的道理,这里的同步锁是自各的对象实例,3个线程互不影响,没有互斥作用

由此得知,synchronized在方法上锁的是对象实例,在代码块里锁的是括号里的对象。别的线程想要拿到锁,就必须等待当前线程执行完成并释放锁,才能再次给对象加锁,达到线程同步互斥作用。
为了提升线程执行效率,就要最小化同步代码块,最小化锁粒度。

上面使用static实现了线程互斥,其实也可以用同一个对象来实现线程互斥,如下:

class MyThread extends Thread {
    private Sync sync;
    public MyThread(Sync sync) {
        this.sync = sync;
    }
    public void run() {
        sync.test();
    }
}

public class Main {
    public static void main(String[] args) {
        Sync sync = new Sync();
        for (int i = 0; i < 3; i++) {
            Thread thread = new MyThread(sync);
            thread.start();
        }
    }
}

运行结果:test开始.. test结束.. test开始.. test结束.. test开始.. test结束
可以看到,线程同步互斥了

更好的做法是,直接锁住这个对象的class对象,与static相同,如下:

class Sync {
    public void test() {
        synchronized (Sync.class) {
            System.out.println("test开始..");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("test结束..");
        }
    }
}

class MyThread extends Thread {
    public void run() {
        Sync sync = new Sync();
        sync.test();
    }
}

运行结果:test开始.. test结束.. test开始.. test结束.. test开始.. test结束
可以看到,线程仍然同步互斥

综上,若需要同步锁,尽量最小化同步块。
学习交流,欢迎加群:64691032


weistar103
26 声望1 粉丝