• 解决线程安全的几种方式


    一、解决线程安全总体可分为两大类:

    1.使用synchronized关键字(可修饰代码块或方法)

    (1)使用synchronized关键字修饰代码块

    public class ThreadDemo {
    	public static void main(String[] args) {
    		ThreadSafe1 thread = new ThreadSafe1();
    		Thread t1 = new Thread(thread);
    		Thread t2 = new Thread(thread);
    		Thread t3 = new Thread(thread);
    		t1.setName("窗口一");
    		t2.setName("窗口二");
    		t3.setName("窗口三");
    		t1.start();
    		t2.start();
    		t3.start();
    	}
    }
    
    class ThreadSafe1 implements Runnable{
    	
    	//定义车票的数量
    	private int ticket = 100;
    	
    	@Override
    	public void run() {		
    		while(true) {
    			synchronized(ThreadSafe1.class) {   //同步监视器为ThreadSafe1.class,它只加载一次,是唯一的,该同步代码块里包含着共享数据的操作
    				if(ticket > 0) {
    					System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票");
    					//车票数量减一
    					ticket--;
    				}else {
    					break;
    				}
    			}
    		}	
    	}	
    }
    

    (2)使用synchronized关键字修饰方法

    public class ThreadDemo {
    	public static void main(String[] args) {
    		ThreadSafe2 thread = new ThreadSafe2();
    		Thread t1 = new Thread(thread);
    		Thread t2 = new Thread(thread);
    		Thread t3 = new Thread(thread);
    		t1.setName("窗口一");
    		t2.setName("窗口二");
    		t3.setName("窗口三");
    		t1.start();
    		t2.start();
    		t3.start();
    	}
    }
    class ThreadSafe2 implements Runnable{
    	
    	//定义车票的数量
    	private int ticket = 100;
    	
    	@Override
    	public void run() {		
    		while(true) {
    			//调用窗口售票方法
    			sale();
    			if(ticket == 0) {
    				break;
    			}
    	    }	
    	}	
    	//实现窗口售票
    	public synchronized void sale() {   //该方法的同步监视器为ThreadSafe2的对象,它是唯一的,这里面也存放着对共享数据的操作
    		if(ticket > 0) {
    			System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票");
    			//车票数量减一
    			ticket--;
    		}
    	}
    }

    2.使用Lock锁方式解决线程安全问题

    public class ThreadDemo {
    	public static void main(String[] args) {
    		ThreadSafe3 thread = new ThreadSafe3();
    		Thread t1 = new Thread(thread);
    		Thread t2 = new Thread(thread);
    		Thread t3 = new Thread(thread);
    		t1.setName("窗口一");
    		t2.setName("窗口二");
    		t3.setName("窗口三");
    		t1.start();
    		t2.start();
    		t3.start();
    	}
    }
    class ThreadSafe3 implements Runnable{
    	
    	//定义车票的数量
        private int ticket = 100;
        private ReentrantLock lock = new ReentrantLock();
    
    	@Override
    	public void run() {
    		while(true) {
    			try {
    				lock.lock();  //对对操作共享数据的代码进行加锁
    				//进行线程休眠,增加其他线程调用的机会
    				try {
    					Thread.sleep(100);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				if(ticket > 0) {
    					System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票");
    					//车票数量减一
    					ticket--;
    				}else {
    					break;
    				}
    			}finally {
    				lock.unlock(); //进行解锁
    			}
    		}		
    	}		
    }

    二、synchronized关键字与Lock锁方式的区别

    (1)两者都可以解决线程安全问题

    (2)synchronized关键字既可以修饰代码块又可以修饰方法;而Lock锁方式只可以修饰代码块

    (3)synchronied关键字修饰的代码块或方法在运行结束后,会自动释放锁;而Lock锁方式需手动为代码块加锁并释放锁

    (4)从性能上,Lock锁方式优于synchronized关键字

  • 相关阅读:
    2018/08/23 cstring中memset()函数的运用
    HDU 6446 Tree and Permutation(赛后补题)
    51NOD 1154 回文串的划分(DP)
    第七章小结_查找
    列出连通集的邻接表解题
    第六章学习小结_初识图
    图的邻接矩阵和邻接表及深度优先搜索
    第五章学习小结
    深深深深深深入虎穴
    括号匹配_进阶篇 ( 7-2 符号配对 )
  • 原文地址:https://www.cnblogs.com/li666/p/11131277.html
Copyright © 2020-2023  润新知