Java多线程-4 Lock Objects to Speed up multi-thread code

方法同步vs代码块同步

关于同步方法和同步代码块的争论
- 同步方法获取的是整个对象的锁。这意味着,其他线程在该方法被运行时不能使用任何的同步方法。
- 同步代码块获取的是synchronized关键字后括号中的内容的关于该对象的锁。
所以:如果你想锁的是整个对象,用synchronized方法。如果你想保证对象的其他部分对其他线程可访问,则应当使用synchronized代码块。
取舍:如果你小心谨慎地选取被锁的对象,同步代码块将会产生更少的竞争,因为整个对象/class并没有被锁住。
这些同样应用于静态方法:同步静态方法将会锁住整个类对象;而同步代码块锁住的只是小括号之间的内容。
翻译过来后很生涩,如果实在看不下去,建议自己看英文版本的链接吧����。

#synchronized on multiple shared object

在多个对象上同步的另一应用:线程执行需要多种资源情形:
final Object foo;
final Object bar;
Runnable tObj = new Runnable {
    public void run() {
        while(true) {
            //sync #1
            synchronized(foo) {
                synchronized(bar) {
                //sync foo
                }
            }
            //More code foo
            //Some more code
            //sync #2
            synchronized(bar) {
                synchronized(foo) {
                //sync foo
                }
            }
        }
    }
}
Thread t1 = new Thread(tObj);
Thread t2 = new Thread(tObj);

这样问题就来了:死锁!!!
当运行到某个时间节点时有如下情形–t1得到了foo同时等待 t2释放bar;t2得到了bar同时等待 t1释放foo.
具体内容后面有涉及,这里有关于上述代码的完整讲解。

Show me the code

  • 具体代码
package com.fqyuan.blog;

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

/* * List 并不是线程安全的,所以多个线程对同一个list对象写操作时就可能出现异常。 * 1.这里可以直接synchronized process()方法,但这样多线程执行效率低下。 * 2.同样可以synchronized stageOne()和stageTwo(),同样多线程只是按顺序完成,效率低下。 * 3.所以这里应用的是代码块机制。 */
public class SynOnMulti {

    public static void main(String[] args) {
        SynOnMultiUtil.demonstrate();
    }

}

class SharedObject {
    private List<Integer> list1 = new ArrayList<>();
    private List<Integer> list2 = new ArrayList<>();

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    private Random random = new Random();

    private /* synchronized */void stageOne() {
        synchronized (lock1) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list1.add(random.nextInt(100));
        }
    }

    private /* synchronized */void stageTwo() {
        synchronized (lock2) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list2.add(random.nextInt(100));
        }
    }

    public void process() {
        for (int i = 0; i < 100; i++) {
            stageOne();
            stageTwo();
        }
    }
}

class SynOnMultiUtil {
    public static void demonstrate() {
        long startTime = System.currentTimeMillis();
        SharedObject sharedObject = new SharedObject();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                sharedObject.process();
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                sharedObject.process();
            }
        });
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Total time taken is: " + (endTime - startTime));
    }
}
  • 运行结果
    1. 不加同步机制:运行很快,但可能有异常。
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 109
    at java.util.ArrayList.add(ArrayList.java:459)
    at com.fqyuan.blog.SharedObject.stageOne(SynOnMulti.java:37)
    at com.fqyuan.blog.SharedObject.process(SynOnMulti.java:54)
    at com.fqyuan.blog.SynOnMultiUtil$1.run(SynOnMulti.java:67)
    at java.lang.Thread.run(Thread.java:745)
Total time taken is: 2433

2.同步在process上

Total time taken is: 4711

3.理论结果

Total time taken is: 2432

Get detailed code and notes @ github.

你可能感兴趣的:(java,多线程,对象,同步)