随笔:多线程的碎碎念

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

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()。上面的基本程序不是多线程程序,所以执行过程如下图所示:

1036292-20170111163422588-2061714546.png

最终结果为:

1036292-20170111163459025-1510641430.png

此时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,我们现在没有进行任何的同步代码,所以执行过程如下:

1036292-20170111164138681-235220240.png

执行的结果如下:

1036292-20170111164207385-391091267.png

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

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

1036292-20170111165108119-1205383804.png

执行的结果如下:

1036292-20170111165227744-1740026908.png

因为加了同步,确保了每次只有一个线程能够访问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++));
        }
    }

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

1036292-20170111165705447-1790529754.png

执行结果如下:

1036292-20170111165733275-1708624339.png

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

转载于:https://www.cnblogs.com/fang-jie/p/6641806.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值