博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程安全
阅读量:4539 次
发布时间:2019-06-08

本文共 7162 字,大约阅读时间需要 23 分钟。

多线程的并发执行可以提高程序运行的效率,但当多个线程去处理同一个资源时,就容易产生一些安全问题。如模拟抢票程序,如果不加线程安全处理的话,就很容易多个线程抢到同一张票,或者出现余票为负数的情况。

synchronized关键字,就是用来控制线程同步的,保证我们的线程在多线程环境下,synchronized块或synchronized方法中的内容不被多个线程同时执行,确保我们数据的完整性。(在run方法里使用synchronized块,或在实现多线程方法里新建synchronized方法)

案例一,抢票程序

1 package cn.ftf.threadsafe; 2  3 public class SafeTest01 { 4     public static void main(String[] args) { 5         Safe12306 safe=new Safe12306(); 6     Thread th=new Thread(safe); 7     Thread th1=new Thread(safe); 8     Thread th2=new Thread(safe); 9     th1.start();10     th2.start();11     th.start();12     13     }14 }15 class Safe12306 implements Runnable{16         private int i=10;17         private boolean flag=true;18         public void run() {19             while(flag)20             test();21     }22         public synchronized void test() {  //synchronized方法,为提高效率,最好使用synchronized块23             if(i<=0) {24                 flag=false;25                 return;    26             }27                 try {28                     Thread.sleep(200);29                 } catch (InterruptedException e) {30                     e.printStackTrace();31                 }32                 System.out.println(i--);33         }    34         35         //优化,尽可能锁定合理的范围,是指数据的完整性36         public void test2() {37             if(i<=0) {    //考虑的是没有票的情况38                 flag=false;39                 return;40             }41             synchronized (this) {42                 if(i<=0) {    //多重检测。//考虑的是最后一张票的情况43                     flag=false;44                     return;45                     46                 }47                 try {48                     Thread.sleep(200);49                 } catch (InterruptedException e) {50                     e.printStackTrace();51                 }52                 System.out.println(i--);53         }    54     }        55         56 }

案例二,多人操作一个账户取钱

1 package cn.ftf.threadsafe; 2 /** 3  *多人操作同一账户取钱 取钱 4  * @author 房廷飞 5  * 6  */ 7 public class SafeTest02 { 8     public static void main(String[] args) { 9         Account acc=new Account(100, "礼金");10         Drawing you=new Drawing(acc, 80);11         Drawing she=new Drawing(acc, 90);12         new Thread(you,"可悲的你").start();13         new Thread(she,"happy的她").start();14     }15 16 }17 class Account{18     int money;19     String name;20     public Account(int money, String name) {21         super();22         this.money = money;23         this.name = name;24     }25 }26 //模拟取款27 class Drawing implements Runnable{28     Account account;29     int drawMoney;  //取地钱数30     int packetTotal;  //口袋的钱数31 32     public Drawing(Account account, int drawMoney) {33         super();34         this.account = account;35         this.drawMoney = drawMoney;36     }37 38     @Override39     public void run() {40         synchronized (account) {41             if(account.money-drawMoney>0) {42                 account.money-=drawMoney;43                 packetTotal+=drawMoney;44                 System.out.println(Thread.currentThread().getName()+"账户余额"+account.money);45                 System.out.println(Thread.currentThread().getName()+"口袋里的钱"+packetTotal);        46             }else {47                 System.out.println(Thread.currentThread().getName()+"取款失败,余额不足!");48             }49             }50     }51 }52

案例三  操作容器,多线程向容器里添加数据会有数据丢失或覆盖的情况

1 package cn.ftf.threadsafe; 2  3 import java.util.ArrayList; 4 import java.util.List; 5  6 /** 7  * 操作容器,多线程向容器里添加数据会有数据丢失或覆盖的情况 8  * @author 房廷飞 9  *10  */11 public class UnsafeTest03 {12     public static void main(String[] args) throws InterruptedException {13         List
list=new ArrayList();14 for(int i=0;i<10000;i++) {15 new Thread(()->{16 synchronized (list) {17 list.add(Thread.currentThread().getName());18 }19 }).start();20 }21 Thread.sleep(2000);22 System.out.println(list.size());23 }24 25 }

涉及多线程读写的容器还可以使用CopyOnWriteArrayList类来创建容器,其内部维护了一个安全的用于线程操作的容器,也是用的synchronized代码块实现的容器安全。

1 import java.util.ArrayList; 2 import java.util.concurrent.CopyOnWriteArrayList; 3 import java.util.List; 4  5 public class SynContainer { 6     public static void main(String[] args) throws InterruptedException { 7         CopyOnWriteArrayList
list = new CopyOnWriteArrayList
(); 8 for(int i=0;i<10000;i++) { 9 new Thread(()->{10 list.add(Thread.currentThread().getName());11 }) .start();12 }13 Thread.sleep(10000);14 System.out.println(list.size());15 }16 }

 

下面写一个多线程(多用户)买电影票的程序

包内包含三个文件,影院类,用户类和测试类:Cinema.java  ,  Person.java  ,  Test.java

 

 

 

 

 Cinema.java :共同操作的对象

1 package cn.ftf.cinema; 2  3 import java.util.ArrayList; 4 import java.util.List; 5  6 public class Cinema{ 7     public List
getTicket() { 8 return ticket; 9 }10 public void setTicket(List
ticket) {11 this.ticket = ticket;12 }13 private List
ticket;14 private String name;15 public Cinema(List
ticket, String name) {16 super();17 this.ticket = ticket;18 this.name = name;19 System.out.println(name+"欢迎你!现有余座:"+ticket.toString());20 }21 public boolean sell(List needTicket){22 List
copy=new ArrayList
();23 copy.addAll(ticket);24 25 copy.removeAll(needTicket);26 if(ticket.size()-copy.size()!=needTicket.size()) {27 return false;28 }29 ticket=copy;30 return true;31 }32 }

Person.java  实现多线程的对象

1 package cn.ftf.cinema; 2  3 import java.util.List; 4  5 public class Person implements Runnable{ 6     Cinema ci; 7     private String pname; 8     private List needTicket; 9     public Person(Cinema ci, String pname, List  needTicket) {10         super();11         this.ci = ci;12         this.pname = pname;13         this.needTicket = needTicket;14     }15     @Override16     public void run() {17         synchronized (ci) {18             boolean flag=ci.sell(needTicket);19             if(flag) {20                 System.out.println(pname+"购票成功,座位:"+needTicket);21                 22             }else {23                 System.out.println(pname+"购票失败,余票不足!");24             }25         }26     }27 }

Test.java    测试类

1 package cn.ftf.cinema; 2  3 import java.util.List; 4  5 public class Person implements Runnable{ 6     Cinema ci; 7     private String pname; 8     private List needTicket; 9     public Person(Cinema ci, String pname, List  needTicket) {10         super();11         this.ci = ci;12         this.pname = pname;13         this.needTicket = needTicket;14     }15     @Override16     public void run() {17         synchronized (ci) {18             boolean flag=ci.sell(needTicket);19             if(flag) {20                 System.out.println(pname+"购票成功,座位:"+needTicket);21                 22             }else {23                 System.out.println(pname+"购票失败,余票不足!");24             }25         }26     }27 }

其中还包含了集合类List的部分使用,增删,复制等

 

转载于:https://www.cnblogs.com/fangtingfei/p/11255884.html

你可能感兴趣的文章
ASP.net 内置对象
查看>>
QT使用mysql
查看>>
判断有无网
查看>>
php开发环境搭建
查看>>
HTML5表单那些事
查看>>
Spring MVC 学习总结(五)——校验与文件上传
查看>>
Spring 4 官方文档学习 Spring与Java EE技术的集成
查看>>
cocos+kbe问题记录
查看>>
自动化测试框架selenium+java+TestNG——配置篇
查看>>
测量标准体重
查看>>
(转)关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。...
查看>>
SQL*Plus 系统变量之32 - NEWP[AGE]
查看>>
Spring配置文件总结
查看>>
4.三角形面积
查看>>
基础-事务
查看>>
MAC下安装与配置MySQL [转]
查看>>
ERROR: ld.so: object '/usr/lib64/libtcmalloc.so.4' from LD_PRELOAD cannot be preloaded: ignored
查看>>
爬虫入门【10】Pyspider框架简介及安装说明
查看>>
android面试(4)---文件存储
查看>>
(转载) 标准C中的字符串操作函数
查看>>