您的位置 首页 java

多线程同步锁的使用范例 干货

此文章是转载的,因为自己看了,感觉特别好。

用一个卖票的例子来示范 多线程 操作一个对象时,同步锁的使用。

先新建一个SaleRunnable类实现Runnable接口,用于表示“卖票”过程:

 class SaleRunnable implements Runnable { 

如上,一共有20张票,每卖出一张票,则打印卖出此票的线程名和票的序号。这个代码里没有加锁。

然后在主程序创建三个 线程 ,传入同一个SaleRunnable对象,三个线程名分别为老王,老张,老李:

 SaleRunnable r = new SaleRunnable(); Thread t1 = new Thread(r,"老王"); Thread t2 = new Thread(r,"老张"); Thread t3 = new Thread(r,"老李");12341234 

然后调用线程的 start ()方法启动三个线程:

 t1.start(); 

运行结果如下:

08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第1张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第2张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第3张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第4张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第5张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第6张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第7张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第8张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第9张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第10张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第11张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第12张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第13张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第14张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第15张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第16张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第17张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第18张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第19张票08-26 12:55:56.011 28300-28316/? D/Test: 老张卖出了第20张票08-26 12:55:56.011 28300-28315/? D/Test: 老王卖出了第12张票123456789101112131415161718192021123456789101112131415161718192021 

可见其结果是乱的,重复运行多次,结果不一,但是都没实现正常的卖票效果。为什么呢,因为三个线程在并行操作同一个对象,所以会出现老张的线程和老王的线程都卖出了第12张票的情况,但是这显然是不对的。

怎么办呢,修改下SaleRunnable类,加上锁试试:

 class SaleRunnable implements Runnable { 

如上面所示,把锁加在判断条件里面,运行结果:

08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第1张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第2张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第3张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第4张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第5张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第6张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第7张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第8张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第9张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第10张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第11张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第12张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第13张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第14张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第15张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第16张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第17张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第18张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第19张票08-26 13:15:08.621 15256-15271/? D/Test: 老王卖出了第20张票08-26 13:15:08.631 15256-15273/? D/Test: 老李卖出了第21张票08-26 13:15:08.631 15256-15272/? D/Test: 老张卖出了第22张票12345678910111213141516171819202122231234567891011121314151617181920212223 

结果看,虽然卖票顺序对了,但卖多了也是不正常的,再改下:

 class SaleRunnable implements Runnable { 

运行结果:

08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第1张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第2张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第3张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第4张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第5张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第6张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第7张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第8张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第9张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第10张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第11张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第12张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第13张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第14张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第15张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第16张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第17张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第18张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第19张票08-26 13:31:41.061 31687-31724/? D/Test: 老王卖出了第20张票12345678910111213141516171819201234567891011121314151617181920 

结果是没错,但是票全让老王给卖了,这也不正常,因为我们把锁加在整个卖票操作外面了,一旦老王开始卖票,其他人都没法卖了。再改:

class SaleRunnable implements Runnable {private int ticket = 20;@Override public void run() { while(true) {//判断条件做了修改synchronized(this) {//锁加在循环判断里面,只有满足条件才能执行卖票操作if (ticket > 0) {Log.d("Test",  Thread .currentThread().getName() + "卖出了第" + (20 - ticket + 1) + "张票");ticket--;} else { break;}} try {//这里的操作是为了方便线程间自动切换,如果不加的话,可能结果也是票全让老王线程给卖了Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}}1234567891011121314151617181920212223242512345678910111213141516171819202122232425 

这样修改后结果正常了:

08-26 13:43:24.181 12176-12199/? D/Test: 老王卖出了第1张票08-26 13:43:24.181 12176-12200/? D/Test: 老张卖出了第2张票08-26 13:43:24.181 12176-12201/? D/Test: 老李卖出了第3张票08-26 13:43:27.181 12176-12199/?D/Test: 老王卖出了第4张票08-26 13:43:27.181 12176-12200/?D/Test: 老张卖出了第5张票08-26 13:43:27.181 12176-12201/?D/Test: 老李卖出了第6张票08-26 13:43:30.181 12176-12199/?D/Test: 老王卖出了第7张票08-26 13:43:30.181 12176-12200/?D/Test: 老张卖出了第8张票08-26 13:43:30.181 12176-12201/?D/Test: 老李卖出了第9张票08-26 13:43:33.181 12176-12199/?D/Test: 老王卖出了第10张票08-26 13:43:33.181 12176-12200/?D/Test: 老张卖出了第11张票08-26 13:43:33.181 12176-12201/?D/Test: 老李卖出了第12张票08-26 13:43:36.181 12176-12199/?D/Test: 老王卖出了第13张票08-26 13:43:36.181 12176-12200/?D/Test: 老张卖出了第14张票08-26 13:43:36.191 12176-12201/?D/Test: 老李卖出了第15张票08-26 13:43:39.181 12176-12199/?D/Test: 老王卖出了第16张票08-26 13:43:39.181 12176-12200/?D/Test: 老张卖出了第17张票08-26 13:43:39.191 12176-12201/?D/Test: 老李卖出了第18张票08-26 13:43:42.181 12176-12199/?D/Test: 老王卖出了第19张票08-26 13:43:42.181 12176-12200/?D/Test: 老张卖出了第20张票12345678910111213141516171819201234567891011121314151617181920 

因此多个线程对同一个线程进行操作时,加锁是有效的解决冲突的方式,但是加到哪里一定要多多思考。

文章来源:智云一二三科技

文章标题:多线程同步锁的使用范例 干货

文章地址:https://www.zhihuclub.com/186346.shtml

关于作者: 智云科技

热门文章

网站地图