zoukankan      html  css  js  c++  java
  • 多线程安全和线程同步

    问题

    线程不安全问题

    在多个线程使用同一个资源的时候,有可能存在一个资源被一个线程占有,但一系列操作(原子操作:不可再分割的操作)并未执行完成,执行过程中的资源被其他线程拿去用了。

    同步

    在一个线程执行原子操作时,其他线程不能占有资源

    1.同步代码块

    同步锁在括号中,是线程共同享有的资源

    @Override
    public void run() {
    		for (int i = 0; i < 50; i++) {
    			String name = Thread.currentThread().getName();
    			synchronized (this) {//同步锁,线程共同享有的资源,这里的this是指Apple对象
    			if (num > 0) {
    				try {
    					Thread.sleep(10);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				System.out.println(name + "吃了第" + num-- + "个苹果");
    			}
    		}
    	}
    }
    

    2.同步方法(不能同步run方法)

    使用synchronized来修饰方法,对于非静态方法,同步锁是this;对于非静态方法,同步锁是当前方法所在类的字节码对象 类名.class

    @Override
    public void run() {
    	for (int i = 0; i < 50; i++) {
    		test();
    	}
    }
    
    private synchronized void test() {
    	String name = Thread.currentThread().getName();
    	if (num > 0) {
    		try {
    			Thread.sleep(10);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println(name + "吃了第" + num-- + "个苹果");
    	}
    }
    

    3.锁机制

    synchronized采用了自动加锁和释放锁的机制,手动加锁的方法更加透明,功能更加强大

    package java_study;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class Apple3 implements Runnable {
    	public int num = 50;
    	//1.由于 Lock 是一个接口,使用其实现类 ReentrantLock 获得一个锁对象
    	private final Lock lock = new ReentrantLock();
    	@Override
    	public void run() {
    		for (int i = 0; i < 50; i++) {
    			eat();
    		}
    	}
    
    	private void eat() {
    		//2.在方法的开始加锁吗,需要使用try-finally保证释放锁的进行
    		lock.lock();
    		try {
    			if (num > 0) {
    				Thread.sleep(10);
    				String name = Thread.currentThread().getName();
    				System.out.println(name + "吃了第" + num-- + "个苹果");
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		} finally {
    			//3.释放锁
    			lock.unlock();
    		}
    	}
    
    }
    
    public class ClockDemo {
    	public static void main(String[] args) {
    		Apple3 a = new Apple3();
    		new Thread(a, "A").start();
    		new Thread(a, "B").start();
    		new Thread(a, "C").start();
    	}
    }
    

    !同步的优缺点:

    • 使用synchronized提高了线程安全性,降低了性能,尽量减小作用域 如:StringBuffer类 ArrayList HashMap
    • 不适用synchronized提升了性能。降低了线程安全性 如:StringBuilder类 Vector Hashtable

    !Sleep 对锁的影响

    • Sleep 不会导致锁丢失,会一直占用资源直到从 sleep 唤醒
  • 相关阅读:
    JAVA使用POI如何导出百万级别数据
    Excel最多可存多少行,多少列?
    jvm参数调优
    迭代器相应型别
    指向NULL的类
    const T & 的适用范围
    函数前修饰const与函数名后修饰const
    继承中赋值函数的注意点
    string类的简要实现
    malloc/free与new/delete的不同及注意点
  • 原文地址:https://www.cnblogs.com/cenzhongman/p/7305789.html
Copyright © 2011-2022 走看看