重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要介绍Java多线程同步问题的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
创新互联建站是创新、创意、研发型一体的综合型网站建设公司,自成立以来公司不断探索创新,始终坚持为客户提供满意周到的服务,在本地打下了良好的口碑,在过去的十多年时间我们累计服务了上千家以及全国政企客户,如成都活动板房等企业单位,完善的项目管理流程,严格把控项目进度与质量监控加上过硬的技术实力获得客户的一致表扬。
简单了解下在操作系统中进程和线程的区别:
进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。
多进程是指操作系统能同时运行多个任务(程序)。
多线程是指在同一程序中有多个顺序流在执行。首先存钱取钱的这个操作,应该是线程操作的,可以有很多的顾客,这意思就是得有多个线程,多个线程之间共同操作一个银行,银行的金额就需要同步。才能保证线程安全。
所以,下面就把这个代码的实例放这,有不对的地方,还请指出来哈。因为有个老铁问这个多线程的代码。
首先是银行,这个对象model的创建。
package com.lxk.threadTest.bank; /** * 银行model,一个总金额属性。 ** * @author lxk on 2017/6/26 */ public class Bank { /** * 给银行个启动资金,不然怎么干生意呢。 */ private int sum = 200; //这个从来不这么用,但也算是正确的一种加锁的机制:同步代码块。 //Object obj = new Object(); /** * 存钱 * 要是不加[synchronized--同步函数],则会出现多线程安全问题。 */ public synchronized void add(int n) { //synchronized (obj) { sum = sum + n; try { Thread.sleep(10); } catch (Exception ignore) { } //当存钱次数变多的时候,就可以发现,存钱的线程确实是2个在交替执行存钱这个动作的。 System.out.println(Thread.currentThread().getName() + "...sum=" + sum); //} } /** * 取钱 * 要是不加[synchronized--同步函数],则会出现多线程安全问题。 */ public synchronized void reduce(int n) { if (sum - n >= 0) { sum = sum - n; } else { System.out.println("bank's money is not enough !"); } try { Thread.sleep(30); } catch (Exception ignore) { } //当存钱次数变多的时候,就可以发现,存钱的线程确实是2个在交替执行存钱这个动作的。 System.out.println(Thread.currentThread().getName() + "...sum=" + sum); } }
在代码里面有存和取2个方法,这2个方法,以及一个总金额,里面有部分被注释掉的代码,那个是简单易懂好理解的,多线程加锁互斥,保证线程间同步的方法。
但是这个是不常用的方法,常用的就是使用synchronized这个关键字来修饰同步方法。
客户对象的model
package com.lxk.threadTest.bank; /** * 顾客,实现runnable()接口,多个人可以一起存钱 * * @author lxk on 2017/6/26 */ public class Customer implements Runnable { /** * 存钱类型 */ static final String TYPE_ADD = "add"; /** * 取钱类型 */ static final String TYPE_REDUCE = "reduce"; /** * 银行 */ private Bank bank; /** * 对钱的操作类型,存钱or取钱 */ private String type; /** * 操作的次数,理论上是个正数 */ private int time; /** * 要存或者取多少钱 */ private int money; public Customer() { } public Customer(Bank bank, String type, int time, int money) { this.bank = bank; this.type = type; this.time = time; this.money = money; } @Override public void run() { for (int x = 0; x < time; x++) { if (TYPE_ADD.equals(type)) { bank.add(money); } else if (TYPE_REDUCE.equals(type)) { bank.reduce(money); } } } }
客户对象,因为可以很多个客户同时访问一个银行,所以,这个存钱取钱的操作就用线程来实现。
属性就构造方法传值了。
main方法
package com.lxk.threadTest.bank; /** * 银行存钱的多线程实例 ** 【需求:】 * 银行有一个金库。 * 有两个储户分别存或者取n * 100。 * 目的:该程序是否有安全问题,如果有,如何解决? *
* 【如何找问题:】 * 1,明确哪些代码是多线程运行代码。 * 2,明确共享数据。 * 3,明确多线程运行代码中哪些语句是操作共享数据的。 * * @author lxk on 2017/6/26 */ public class Main { public static void main(String[] args) { //一个银行and多个客户 Bank bank = new Bank(); int time = 10000; int money = 100; //这个客户存钱 Customer c1 = new Customer(bank, Customer.TYPE_ADD, time, money); //这个客户取钱 Customer c2 = new Customer(bank, Customer.TYPE_REDUCE, time, money); Thread t1 = new Thread(c1); Thread t2 = new Thread(c2); t1.start(); t2.start(); } }
上述代码实际运行效果如下图。
这个存取钱的次数要是小了,就可能会看到2个线程有先后顺序,所以,这个次数咱整多点,然后,就看到如图所示的情况,线程1是取钱的,线程0时存钱的,可以看到2个线程是互相交错执行的,有存有取,没有规律可言。
这个就保证了数据的同步了。
至于如何才能不同步,也就是异常的现象,
你可以把add方法的这个synchronized关键字去掉之后,把次数调小一点改成3次,sum的初始值给设置成0.你再试试代码,
就会发现所谓的不同步现象。
上图的右边就是不同步的结果,2个人每次存100,存三次,总数是不是得,100,200,300,400,500,600.得长。
但是,运行结果却不是的,
这个时候,你再把synchronized给add方法加上去,就会出现左边的图的结果,这个就是正确的结果。
我是为了,有存有取,所以,就又加了个方法。代码就变成上面的样子啦。
差不多都是线程间同步的例子啦。
以上是“Java多线程同步问题的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注创新互联行业资讯频道!