[22]Synchronized代码块与Synchronized函数

版权声明:嘤嘤嘤,小白的东西,大牛们应该看不上吧。 https://blog.csdn.net/qq_37384180/article/details/83511706

一、使用原因

多线程使用原因:

一块大蛋糕太大了,一天内还需要吃完,不然就坏了,一个人吃不完,所以需要两个人吃,但是只有一个勺子,如果A吃的时候不小心把勺子弄丢了。需要花时间找,那么B就不能吃。所以就需要使用多线程。给两个勺子,就算A吃的时候丢了,B也可以不受到影响。继续执行下去。

同步锁的使用原因:

吃蛋糕的时候,因为两个人不停的吃。A吃的快,B吃的慢。就导致了,A吃撑了了,B反而没吃饱。不是我们想看到的事情。所以需要一个抢盘子(同步锁),A抢到盘子先吃四分之一,B等着。等A吃完后,B继续抢。如果抢到了,B吃。如果没抢到,那么A再吃四分之一后,就让给B。

二、代码体现

同步代码块:

synchronized(Object obj){

      //code

}

 同步方法:

public synchronized void method(){//code}

三、代码案例

package com.synchronized_test;

/**
 * 人类
 */
public class Person implements Runnable {
	/* 蛋糕对象 */
	private Cakes c = new Cakes();

	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized (c) {
			while(c.num>0) {
				eat();
				try {
                    //问题!!!后面有讲解
					c.wait(1000);//让A线程停一下,给B线程得到执行的机会
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
    /*吃蛋糕的动作*/
	public void eat() {
		System.out.println(Thread.currentThread().getName() + " eat第" + c.num-- + "份");
	}	
}

package com.synchronized_test;

/**
 * 蛋糕类
 * */
public class Cakes{
	/*数量,分4份*/
	int num=4;
}

package com.synchronized_test;
/**
 * 测试
 * */
public class Demo {
	public static void main(String[] args) {
		Person p=new Person();
		
		Thread A=new Thread(p);
		Thread B=new Thread(p);
		
		A.start();
		B.start();
	}
}

代码解释:

1.共有3个类,测试类,蛋糕类,人类

2.蛋糕类:分成4份。所以属性就是num,为了让代码稍微优化点,就没封装了。

3.人类:线程类,行为是eat(),还有一个实现Runnable接口的run()。eat()中写的是打印输出哪个线程吃的,并且使数量减一。run()中写是只要num>0就不停循环。

4.测试类:创建Person类实例,创建两个线程,并将p作为参数传入两个线程中,开启后,两个线程进入就绪状态。CPU会随机 给予执行权。

问题为什么要写wait(long millis)而不是sleep(long millis),两个代码作用很像。但是会使两个线程处于不同的状态。

sleep(long millis):线程暂时处于TIME_WAITING状态,但是不释放对象锁。也就是说,我就算不继续执行,但我手里还是握着这个对象的锁。我就算不执行,你也别想执行。那么如果这里写sleep(),也只会使A线程执行4次而已。B线程一口都吃不到。

wait():线程释放对象锁,且处于WAITING状态,除非被手动唤醒,否则将不会拥有CPU的执行资格,更别说CPU执行权了。

wait(long millis):线程释放对象锁,处于TIME_WAITING状态,与无参的wait()的区别就是等到millis的时间到了之后,会被自动唤醒。重新争夺对象锁。

四、使用区别

既然同步代码块和同步方法都能同步。那使用哪个?

代码案例:

package com.synchronized_methods;
/**
 * Synchronized1
 * */
public class SynchronizedMethod {
	private AnotherClass a=new AnotherClass();
	/*同步代码块1*/
	public void showA() {
		System.out.println("showA");
		synchronized(a) {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	/*同步函数2*/
	/*同步函数的对象锁是固定的this,跟ShowA不是一个对象锁*/
	public synchronized void showB() {
		System.out.println("showB");
	}
	/*同步代码块2*/
	/*与showB的对象锁是同一个对象锁*/
	public void showC() {
		synchronized(this) {
			System.out.println("showC");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

package com.synchronized_methods;

/**
 * Synchronized2
 * */

public class AnotherClass {
	/*同步代码块1*/
	public void showA() {
		/*与SynchronizedMethod中的showA方法是同一把锁*/
		synchronized (this) {
			System.out.println("showA2");
		}
	}
}

package com.synchronized_methods;

/**
 * 测试类
 * */

public class Demo {
	public static void main(String[] args) {
		SynchronizedMethod s=new SynchronizedMethod();
		AnotherClass a=new AnotherClass();
		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				s.showA();
				a.showA();
			}
		}).start();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				s.showC();
				s.showB();
			}
		}).start();
	}
}

运行结果:

执行情况:先执行了showA()和showC()后,执行了隔了1秒执行了showB(),再隔了2秒执行了showA()

showA
showC
showB
showA2

代码解释:

问题1:为什么执行了showA()后没有暂停又直接执行了showC()?

解答:很明显,Synchronized代码块就是为了对象锁不让其他线程在执行中间插入。所以之所以能直接执行showC(),完全是因为两个方法用的不是同一个锁。showA()用的是AnotherClass类的对象,而showC()用的是当前对象。所以能够无视showA()方法中的Thread.sleep(3000)

问题2:那为什么可以之后停了1秒之后又执行了showB()呢?

解答:因为showB()中,没有写同步代码块,而是用同步修饰了方法,所以之所以等1秒,也是因为同步方法的对象锁,跟showC()中的对象锁是同一个对象锁。所以说,同步方法的对象锁其实就是this

五、全文总结:

1、同步代码块:允许同一个线程中,同步的时候,可以有多种同步情况。因为代码块中的参数为Object obj

2、同步方法:只允许this这一种同步。

猜你喜欢

转载自blog.csdn.net/qq_37384180/article/details/83511706