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

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

java多线程——多线程的安全问题

模拟火车票售票程序:

1 /** 2  * 售票案例:售票的动作被多个线程同时执行 3  */ 4 class Ticket implements Runnable{ 5     //描述票的数量 6     private int tickets=100; 7     //售票,线程任务中通常都有循环结构 8     @Override 9     public void run() {10         while(true) {11             if(tickets>0) {
//此处可能线程1,2,3,4都进入,那么就可能出现输出tickets为负值的错误数据12 try {13 Thread.sleep(200);14 } catch (InterruptedException e) {15 //待处理16 }17 System.out.println(Thread.currentThread().getName()+"------"+tickets--);18 } 19 }20 }21 }22 23 public class TicketSellDemo {24 public static void main(String[] args) {25 Ticket t=new Ticket();26 27 Thread t1=new Thread(t);28 Thread t2=new Thread(t);29 Thread t3=new Thread(t);30 Thread t4=new Thread(t);31 32 t1.start();33 t2.start();34 t3.start();35 t4.start();36 }37 }

1、线程安全问题出现的原因:

(1)多个线程操作共享的数据;

(2)线程任务操作共享数据的代码有多条(多个运算)。

2、解决思路:

只要让一个线程在执行线程任务时将多条操作共享数据的代码执行完,在执行过程中,不要让其他线程参与运算。那么如何在代码中体现呢?java中解决此问题:

(1)通过代码块完成,这个代码块叫做同步代码块,使用关键字synchronized。

1 /** 2  * 售票案例:售票的动作被多个线程同时执行 3  */ 4 class Ticket implements Runnable{ 5     //描述票的数量 6     private int tickets=20; 7     //售票,线程任务中通常有循环结构 8     private Object obj=new Object();//用来处理安全问题 9     @Override10     public void run() {11         while(true) {12             synchronized(obj)13             {14                 if(tickets>0) {15                     try { Thread.sleep(200);} catch (InterruptedException e) {
/*待处理*/}16 System.out.println(Thread.currentThread().getName()+"------"+tickets--);17 } 18 }19 }20 }21 }22 23 public class TicketSellDemo {24 public static void main(String[] args) {25 Ticket t=new Ticket();26 27 Thread t1=new Thread(t);28 Thread t2=new Thread(t);29 Thread t3=new Thread(t);30 Thread t4=new Thread(t);31 32 t1.start();33 t2.start();34 t3.start();35 t4.start();36 }37 }
View Code

同步的前提:必须保证多个线程中使用的是同一个锁。例如:若将上述代码中synchronized(obj)改为synchronized(new Object()),安全问题仍然不能解决。

(2)使用同步函数(方法)

同步函数使用的锁是this,静态同步函数使用的锁是字节码文件对象,类名.class.

1 /** 2  * 售票案例:售票的动作被多个线程同时执行 3  */ 4 class Ticket implements Runnable{ 5     //描述票的数量 6     private int tickets=20; 7     //售票,线程任务中通常有循环结构 8     @Override 9     public void run() {10         //method1();11         while(true) {12             sale();13         }14     }15     16     public synchronized void sale() {17             if(tickets>0) {18             //    try { Thread.sleep(200);} catch (InterruptedException e) {/*待处理*/}19                 System.out.println(Thread.currentThread().getName()+"------"+tickets--);20             }    21     }22 }23 24 public class TicketSellDemo {25     public static void main(String[] args) {26         Ticket t=new Ticket();27         28         Thread t1=new Thread(t);29         Thread t2=new Thread(t);30         Thread t3=new Thread(t);31         Thread t4=new Thread(t);32         33         t1.start();34         t2.start();35         t3.start();36         t4.start();37     }38 }
View Code

同步函数和同步代码块有什么区别?

同步函数使用的锁是固定的this,同步代码块使用的锁可以是任意对象。当线程任务只需要一个同步时完全可以使用同步函数。当线程任务中需要多个同步时,必须通过锁来区分,这时必须使用同步代码块。同步代码块较为常用。

3、单例懒汉式的并发访问

1 //饿汉式,多线程并发没有问题。 2 /* 3   public class Single { 4         private static final Single instance=new Single(); 5         private Single() {}; 6         public static Single getInstance() { 7             return instance; 8         } 9     }10 */11 12 //懒汉式:存在线程安全问题,需要加上同步机制synchronized13 /*14 public class Single {15     private static Single instance=null;16     private Single() {}17     public static synchronized Single getInstance() {18         if(instance==null) {19             instance=new Single();20         }21         return instance;22     }    23 }24 */25 //但是,同步的出现降低了效率.可以通过双重判断,解决效率问题,减少判断次数26 public class Single {27     private static Single instance=null;28     private Single() {}29     public static Single getInstance() {30         if(instance==null) {31             synchronized(Single.class){32                 if(instance==null) {33                     instance=new Single();34                 }35             }36         }37         return instance;38     }    39 }
Single

4、死锁

同步的另一个弊端:死锁

情况之一:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步,这时容易引发死锁。

1 class Test implements Runnable{ 2     private boolean flag; 3     Test(boolean flag){ 4         this.flag=flag; 5     } 6      7     public void run() { 8         if(flag) { 9             while(true) {
//加了循环一定会锁住10 synchronized(Mylock.lockA) {11 System.out.println(Thread.currentThread().getName()+"....if...lockA");12 synchronized(Mylock.lockB) {13 System.out.println(Thread.currentThread().getName()+"....if...lockB");14 }15 }16 }17 18 }else {19 while(true) {20 synchronized(Mylock.lockB) {21 System.out.println(Thread.currentThread().getName()+"....else....lockB");22 synchronized(Mylock.lockA) {23 System.out.println(Thread.currentThread().getName()+"....else.....lockA");24 }25 }26 }27 }28 }29 }30 31 class Mylock{32 public static final Object lockA=new Object();33 public static final Object lockB=new Object();34 }35 public class Deadlocks {36 public static void main(String[] args) {37 Test t1=new Test(true);38 Test t2=new Test(false);39 Thread t11=new Thread(t1);40 Thread t22=new Thread(t2);41 t11.start();42 t22.start();43 }44 45 46 }
Deadlocks

 

转载于:https://www.cnblogs.com/hopeyes/p/9740825.html

你可能感兴趣的文章
浅析x86架构中cache的组织结构
查看>>
JDateTime
查看>>
深入了解MyBatis二级缓存
查看>>
Cloud Test 单页面即时监测功能上线!
查看>>
一分钟了解阿里云产品:阿里云解析五大热点技术问题分析
查看>>
mysql TableMap id递增问题
查看>>
我不是大佬!
查看>>
你也许不知道的Vuejs - 使用ES6快乐的玩耍
查看>>
我理解的javascript事件循环(一)
查看>>
实现基于注解(Annotation)的数据库框架(三)自定义注解(Annotation)
查看>>
手机动态码登录
查看>>
JavaScript 字符串连接性能比较
查看>>
基于element-ui实现table可配置化
查看>>
项目遇到的问题或处理办法
查看>>
PHP中类和文件的代码注释规范
查看>>
three.js学习资料整理
查看>>
Vue根据条件添加click事件
查看>>
JavaScript发布订阅者模式
查看>>
【Vue学习第三天】组件的使用
查看>>
计算机网络知识点总结(一)-物理层
查看>>