随笔:多线程的碎碎念

这次举一个例子来记录如何使用多个锁来加快程序运行速度,下面是基本的程序:

class Worker {
    private int count1 = 0;
    private int count2 = 0;
    public void stageOne() {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " count1: " + (count1++));
    }

    public void stageTwo() {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " count2: " + (count2++));  
    }

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

    public void main() {
        System.out.println("Starting ... ");
        long start = System.currentTimeMillis();
        process();
        long end = System.currentTimeMillis();
        System.out.println("time take: " + (end - start));
        System.out.println("count1: " + count1 + "; count2: " + count2);
    }
}
public class MultipleLocksTest {
    public static void main(String[] args) {
        new Worker().main();
    }
}

程序大概的意思是在Worker类中有两个变量count1count2,分别在stageOne()stageTwo()中增加一,并输出此时是哪个线程增加的。process()迭代100次,每次都执行stageOne()stageTwo()。上面的基本程序不是多线程程序,所以执行过程如下图所示:

最终结果为:

此时main函数是唯一的线程,以此执行stageOne()stageTwo()

现在我们加上两个线程,代码如下:

public void main() {
    System.out.println("Starting ... ");
    long start = System.currentTimeMillis();
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            process();
        }
    });

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            process();
        }
    });

    t1.start();
    t2.start();
    try {
        t1.join();
        t2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    System.out.println("time take: " + (end - start));
    System.out.println("count1: " + count1 + "; count2: " + count2);
}

现在有两个线程t1和t2,将会访问共享的count1,count2,我们现在没有进行任何的同步代码,所以执行过程如下:

执行的结果如下:

Thread-0和Thread-1将能够同时访问count1,count2,导致最终的结果不等于200。

现在我们分别给stageOne()stageTwo()加上synchronized同步语句,那么执行的过程如下:

执行的结果如下:

因为加了同步,确保了每次只有一个线程能够访问count1和count2, 所以执行时间比没有加同步的多了1倍。

但是这种情况下,如果Thread-0获得了Worker对象的内部锁,在执行stageOne()过程中,Thread-1不能执行stageOne()也不能执行stageTwo(),只有执行万stageOne()或者stageTwo()时,线程会释放内部锁,其他线程才能执行stageOne()或者stageTwo(),这也导致了在同一只能执行一个方法,要么stageOne(),要么stageTwo。因为这里两个方法写的是不同的变量,互相之间是独立的,所以我们可以这么修改程序,使执行速度加快:

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

    public void stageOne() {
        synchronized (lock1) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " count1: " + (count1++));
       }
    }

    public void stageTwo() {
        synchronized (lock2) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " count2: " + (count2++));
        }
    }

现在的执行过程如下所示:

执行结果如下:

可见,现在Thread-0在执行stageOne()时,Thread-1可以执行stageTwo(),最后的执行时间也少了1倍。

posted @ 2017-03-29 21:14  传奇魔法师  阅读(186)  评论(0编辑  收藏  举报