• java复习-线程的同步和死锁


    线程的同步和死锁

    同步问题引出

    当多个线程访问同一资源时,会出现不同步问题。比如当票贩子A(线程A)已经通过了“判断”,但由于网络延迟,暂未修改票数的间隔时间内,票贩子B(线程B)也通过了“判断”。此时,若票数只剩下了最后一张,则会出现两个线程同时通过判断并最终会修改票数,出现错误(票数为0或-1)。
    在这里插入图片描述

    线程同步处理

    解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其它线程外面等待。
    在这里插入图片描述

    现这把锁的功能,就可以使用 synchronized 关键字来实现,利用此关键字可以定义同步方法或同步代码块, 在同步代码块的操作里面的代码只允许一个线程执行。

    1. 同步代码块

    synchronized(同步对象){
        同步代码操作;
    }
    
    • 1
    • 2
    • 3

    一般要进行同步对象处理的时候可以采用当前对象 this 进行同步。
    卖票范例(同步代码块版):

    class MyThread implements Runnable { // 线程的主体类
    	private int ticket = 5;
    
    	@Override
    	public void run() { // 线程的主体方法
    		while(true) {
    			synchronized(this) { // 每一次只允许一个线程进行访问
    				if (this.ticket > 0) {
    					try {
    						Thread.sleep(100);  // 模拟网络延迟
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + "买票,ticket = " + this.ticket --);				
    				} else { 
    					System.out.println("-----票已售完-----");
    					break;
    				}
    			}
    		}
    	}
    }
    public class ThreadDemo {
    	public static void main(String[] args) {
    		MyThread mt = new MyThread();
    		new Thread(mt,"票贩子A").start(); 
    		new Thread(mt,"票贩子B").start(); 
    		new Thread(mt,"票贩子C").start(); 
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    结果:

    票贩子A买票,ticket = 5
    票贩子C买票,ticket = 4
    票贩子C买票,ticket = 3
    票贩子C买票,ticket = 2
    票贩子B买票,ticket = 1
    -----票已售完-----
    -----票已售完-----
    -----票已售完-----

    加入同步处理之后,程序的整体的性能下降了。同步实际上会造成性能的降低。

    2. 同步方法

    只需要在方法定义上使用synchronized 关键字即可。

    class MyThread implements Runnable { // 线程的主体类
    	private int ticket = 5;
    
    	public synchronized boolean sale() { // 每一次只允许一个线程进行访问该方法
    		if (this.ticket > 0) {
    			try {
    				Thread.sleep(100);  // 模拟网络延迟
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println(Thread.currentThread().getName() + "买票,ticket = " + this.ticket --);
    			return true;
    		} else { 
    			System.out.println("-----票已售完-----");
    			return false;
    		}
    	}
    	
    	@Override
    	public void run() {
    		while(this.sale()) {}
    	}
    }
    public class ThreadDemo {
    	public static void main(String[] args) {
    		MyThread mt = new MyThread();
    		new Thread(mt,"票贩子A").start(); 
    		new Thread(mt,"票贩子B").start(); 
    		new Thread(mt,"票贩子C").start(); 
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    结果:

    票贩子A买票,ticket = 5
    票贩子A买票,ticket = 4
    票贩子A买票,ticket = 3
    票贩子C买票,ticket = 2
    票贩子C买票,ticket = 1
    -----票已售完-----
    -----票已售完-----
    -----票已售完-----

    在日后学习 Java 类库的时候会发现,系统中许多的类上使用的同步处理采用的都是同步方法。

    线程死锁

    死锁是在进行多线程同步的处理之中有可能产生的一种问题,所谓的死锁指的是若干个线程彼此互相等待的状态。
    若干个线程访问同一资源时一定要进行同步处理,而过多的同步会造成死锁。

  • 相关阅读:
    Java程序员该如何进阶?资深阿里P8通过十年经验送你一些经验和建议!
    混淆矩阵和数据不平衡 (3/3)
    海外云主机的选择要注意什么?
    将目录下的所有pdf文件都转换为对应名字的png图片
    Stable Diffusion 系统教程 | 强大的ControlNet 控制网
    JS基础--运算符(注意点)
    leetcode896:单调数列
    [附源码]计算机毕业设计基于Springboot的手机电商网站
    旅游APP外包开发注意事项
    代码的工厂模式
  • 原文地址:https://blog.csdn.net/qq_41168765/article/details/132856303