java synchronized关键字学习笔记

synchronized(同步锁)关键字是用来解决共享资源的竞争问题。基本上所有的并发模式在解决线程冲突问题时,都是采用序列化访问共享资源的方案。这意味着在任意时刻,只允许一个任务访问共享资源。通常这是通过在代码前加上一条锁语句来实现的,这就使得在给定时刻,只允许一个任务可以运行这段代码。因为锁语句产生了一种互相排斥的效果,这种机制常常被称作互斥量

要控制对共享资源的访问,得先把它装进一个对象。然后把所有想访问这个资源的方法都标记为synchronized。如果某个任务处于对一个标记为synchronized的方法的调用中,那么在这个线程从该方法返回之前,其他所有要调用类中被标记为synchronized的方法都将处于阻塞状态

synchronized void f(){
    
    }
synchronized void g(){
    
    }

所有对象都自动含有单一的锁(也称为监视器)

在使用并发时,将域设置为private是非常重要的,否则,synchronized关键字就不能防止其他任务直接访问域,这将产生冲突

一个任务可以多次获得对象的锁,这表现为在标记为synchronized的一个方法中调用另一个标记为synchronized的方法,甚至可以调用多层。JVM将对调用层数进行计数,直至锁被完全释放计数才被置0。

针对每个类,也有一个锁(作为类Class对象的一部分),所以synchronized static方法可以在类的范围内防止对static数据的并发访问。

每个访问临界共享资源的方法都必须被同步,否则它们就不能正确的工作。

public abstract class IntGenerator {
    
    
    private volatile boolean canceled=false;
    public abstract int next();
    public void cancel() {
    
    canceled=true;}
    public boolean isCanceled() {
    
    return canceled;}
}
public class EvenChecker implements Runnable{
    
    
    private IntGenerator generator;
    private final int id;
    public EvenChecker(IntGenerator g,int ident) {
    
    
    	generator=g;
    	id=ident;
    }
	@Override
	public void run() {
    
    
		// TODO Auto-generated method stub
		while(!generator.isCanceled()) {
    
    
			int val=generator.next();
			if(val%2!=0) {
    
    
				System.out.println(val+" is not even");
			}
			generator.cancel();
		}
	}
    public static void test(IntGenerator gp,int count) {
    
    
    	System.out.println("Press Control-c to exit");
    	ExecutorService exec=Executors.newCachedThreadPool();
    	for(int i=0;i<count;i++) {
    
    
    		exec.execute(new EvenChecker(gp,i));
    	}
    	exec.shutdown();
    }
    public static void test(IntGenerator gp) {
    
    
    	test(gp,10);
    }
}

public class EvenGenerator extends IntGenerator{
    
    
    private int currentEvenValue=0;
    public synchronized int next() {
    
    
    	++currentEvenValue;
    	Thread.yield();
    	++currentEvenValue;
    	return currentEvenValue;
    }
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
        EvenChecker.test(new EvenGenerator());
	}

}

若去掉EvenGenertor中修饰next()方法的synchronized关键字和让步语句,将导致多个线程执行混乱。即一个线程并不会执行两次自加操作。

猜你喜欢

转载自blog.csdn.net/weixin_43916777/article/details/104263308