java多线程之synchronized
2015-11-08 00:00
183 查看
首先来看下一个场景,某电影院某个时间4个窗口同时在卖票,本场电影总共票只有100张,卖完为止。看下实际代码。
![](http://static.oschina.net/uploads/img/201511/08165430_Up57.jpg)
从运行结果来看,发现出现了负数。在实际业务中是不可以的。
从而我们得出一个结论:多个线程访问一个对象中的实例变量,可能会出现`非线程安全`。
synchronized方法
如果在方法上加关键字synchronized,那么就不会出现上面的那个问题。
看到这里有些人就要问了,既然加了锁,我们的代码就只能被一个线程调用,这样岂不是降低了效率,在同步代码的部分并没有多线程并发的情况出现呀?如果你能想到这一点,就说明你对锁的机制了解的差不多了,的确,情况的确如此,因为我们要尽量的缩小同步锁的范围,有什么原则么?所以有时间同步方法并不适合。
synchronized代码块
假如在卖票之前,我们还要去做相关的事。比如我们在美团买了一张票,可能在电影院的系统中,需要去效验下,是不是你在美团买了票,在决定是否出票。这个过程相当耗时,而每个人都是单独的对象去访问,所以是线程安全,但是我们要是用synchronized方法,是不适合的。
从上面的例子我们可以看出,这样也是达到我们要的结果。那么我们不禁要问该如何定义一个锁?
所谓加锁,就是为了防止多个线程同时操作一份数据,如果多个线程操作的数据都是各自的,那么就没有加锁的必要
共享数据的锁对于访问他们的线程来说必须是同一份,否则锁只能私有的锁,各锁个的,起不到保护共享数据的目的,试想一下将 Object lock 的定义放到 run 方法里面,每次都会实例化一个 lock,每个线程获取的锁都是不一样的,也就没有争抢可言,说的在通俗一点甲楼有一个门上了锁,A 要进门,乙楼有一个门上了锁 B 要进门,A 和 B 抢的不是一个门,因此不存在数据保护或者共享;
锁的定义可以是任意的一个对象,该对象可以不参与任何运算,只要保证在访问的多个线程看来他是唯一的即可;
版权声明:本文为博主原创文章,未经博主允许不得转载。
package cn.com.thread; public class TestThread { public static void main(String[] args) { SellTicketThread t=new SellTicketThread(); new Thread(t,"窗口1").start(); new Thread(t,"窗口2").start(); new Thread(t,"窗口3").start(); new Thread(t,"窗口4").start(); } }
package cn.com.thread; public class SellTicketThread extends Thread { private int ticket = 100; @Override public void run() { while (true) { if(sellTicket()){ break; } } } private boolean sellTicket() { try { if (ticket <= 0) { return true; } Thread.sleep(30); } catch (Exception e) { } System.out.println(Thread.currentThread().getName()+":"+(ticket--)); return false; } }
![](http://static.oschina.net/uploads/img/201511/08165430_Up57.jpg)
从运行结果来看,发现出现了负数。在实际业务中是不可以的。
从而我们得出一个结论:多个线程访问一个对象中的实例变量,可能会出现`非线程安全`。
synchronized方法
如果在方法上加关键字synchronized,那么就不会出现上面的那个问题。
package cn.com.thread; public class SellTicketThread extends Thread { private int ticket = 100; @Override public void run() { while (true) { if(sellTicket()){ break; } } } private synchronized boolean sellTicket() { try { if (ticket <= 0) { return true; } Thread.sleep(30); } catch (Exception e) { } System.out.println(Thread.currentThread().getName()+":"+(ticket--)); return false; } }
看到这里有些人就要问了,既然加了锁,我们的代码就只能被一个线程调用,这样岂不是降低了效率,在同步代码的部分并没有多线程并发的情况出现呀?如果你能想到这一点,就说明你对锁的机制了解的差不多了,的确,情况的确如此,因为我们要尽量的缩小同步锁的范围,有什么原则么?所以有时间同步方法并不适合。
synchronized代码块
假如在卖票之前,我们还要去做相关的事。比如我们在美团买了一张票,可能在电影院的系统中,需要去效验下,是不是你在美团买了票,在决定是否出票。这个过程相当耗时,而每个人都是单独的对象去访问,所以是线程安全,但是我们要是用synchronized方法,是不适合的。
package cn.com.thread; public class SellTicketThread extends Thread { private int ticket = 100; private Object lock=new Object(); @Override public void run() { while (true) { if (sellTicket()) { break; } } } private boolean sellTicket() { System.out.println("效验逻辑,耗时10秒"); try { synchronized (lock) { if (ticket <= 0) { return true; } System.out.println(Thread.currentThread().getName() + ":"+ (ticket--)); } Thread.sleep(30); } catch (Exception e) { } return false; } }
从上面的例子我们可以看出,这样也是达到我们要的结果。那么我们不禁要问该如何定义一个锁?
所谓加锁,就是为了防止多个线程同时操作一份数据,如果多个线程操作的数据都是各自的,那么就没有加锁的必要
共享数据的锁对于访问他们的线程来说必须是同一份,否则锁只能私有的锁,各锁个的,起不到保护共享数据的目的,试想一下将 Object lock 的定义放到 run 方法里面,每次都会实例化一个 lock,每个线程获取的锁都是不一样的,也就没有争抢可言,说的在通俗一点甲楼有一个门上了锁,A 要进门,乙楼有一个门上了锁 B 要进门,A 和 B 抢的不是一个门,因此不存在数据保护或者共享;
锁的定义可以是任意的一个对象,该对象可以不参与任何运算,只要保证在访问的多个线程看来他是唯一的即可;
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- C#实现多线程的同步方法实例分析
- 浅谈chuck-lua中的多线程
- C#简单多线程同步和优先权用法实例
- C#多线程学习之(四)使用线程池进行多线程的自动管理
- C#多线程编程中的锁系统(三)
- C#多线程学习之(六)互斥对象用法实例
- 基于一个应用程序多线程误用的分析详解
- C#多线程学习之(三)生产者和消费者用法分析
- C#多线程学习之(一)多线程的相关概念分析
- C#多线程之Thread中Thread.IsAlive属性用法分析
- C#控制台下测试多线程的方法
- Ruby 多线程的潜力和弱点分析
- C#中WPF使用多线程调用窗体组件的方法
- C#如何对多线程、多任务管理(demo)
- C#实现多线程的Web代理服务器实例
- c#实现多线程局域网聊天系统
- PHP使用CURL实现多线程抓取网页
- 浅解关于C#多线程的介绍
- 批处理程序中的“多线程”处理代码