JAVA学习第二十四课(多线程(三))- 线程的同步


继续以卖票为例


一、线程安全问题的解决

同步的第一种表现形式:同步代码块


思路:

将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不允许参与运算的,必须要当期线程把代码执行完毕后,其他线程才可以参与运算

在java中用同步代码块解决这个问题

同步代码块格式:

synchronized(对象)

{

需要被同步的代码部分

}

class Ticket implements Runnable
{
	private int num = 100;
	Object god = new Object();//也可以自定义,建议使用已有的
	public void run()
	{
		while(true)
		{
			synchronized(god) //同步
			{
				if(num>0)
				{
					try 
					{
						Thread.sleep(10);
					} 
					catch (InterruptedException e) 
					{
						// TODO: handle exception
					}
				
	System.out.println(Thread.currentThread().getName()+"..sale.."+num--);	
			}	
			}
		}
	}
}
public class Main 
{
	public static void main(String[] args)
	{
		Ticket t = new Ticket();
		Thread j1 = new Thread(t);
		Thread j2 = new Thread(t);
		Thread j3 = new Thread(t);
		Thread j4 = new Thread(t);
		j1.start(); j2.start(); 
		j3.start(); j4.start();
	}
}

Object的对象就好比一把锁,对同步进行监视操作,当有线程在执行,其他线程不能执行

同步的好处:解决了线程的安全问题

同步的弊端:当一个线程sleep时,释放执行权,执行权会给其他线程,然后进行判断同步锁,判断完又进不去,所以相对以前会降低效率,是在可承受的范围内


二、同步的前提

如果出现,同步后安全问题还存在,就必须了解同步的前提

前提:同步中必须有多个线程并使用同一个锁(一个线程就没必要同步,多个锁就失去同步的价值)


三、同步的第二种表现形式:同步函数


/*
 * 需求:
 * 两个人到银行存钱,每次存10,每个人都是三次
 * 
 * */
class Bank
{
	private int sum;
	private Object obj = new Object();
	//同步代码代码块表现形式
	/*public void add(int num)
	{
		synchronized(obj)
		{
			sum += num;
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		System.out.println("sum = "+sum);
		}
	
	}*/
	//同步函数表现形式
	public synchronized void add(int num)
	{
		sum += num;
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		System.out.println("sum = "+sum);
	}
}
class Custom implements Runnable
{
	private Bank bank = new Bank();
	public void run() 
	{
		for(int i = 0;i<3;i++)
		{
			bank.add(10);
		}
	}
}
class Main
{
	public static void main(String[] args)
	{
		Custom tCustom = new Custom();
		Thread j1 = new Thread(tCustom);
		Thread j2 = new Thread(tCustom);
		j1.start();
		j2.start();
	}
}


验证同步函数的锁是什么?(了解)

class Ticket implements Runnable
{
	private int num = 100;
	Object god = new Object();//也可以自定义,建议使用已有的
	boolean flag = true;
	public void run()
	{
		
		if(flag==true)
		{
				while(true)
		{
			synchronized(this) //同步
			{
				if(num>0)
				{
					try 
					{
						Thread.sleep(10);
					} 
					catch (InterruptedException e) 
					{
						// TODO: handle exception
					}
				
	System.out.println(Thread.currentThread().getName()+"..obj.."+num--);	
			}	
			}
		}
		}
	
		else {
			while(true)
			this.show();
		}
	}
	public synchronized void show()
	{
		if(num>0)
		{
			try 
			{
				Thread.sleep(10);
			} 
			catch (InterruptedException e) 
			{
				// TODO: handle exception
			}
		
System.out.println(Thread.currentThread().getName()+"..fu.."+num--);	
	
	}
}
}
class Main 
{
	public static void main(String[] args)
	{
		Ticket t = new Ticket();
		Thread j1 = new Thread(t);
		Thread j2 = new Thread(t);
		
		j1.start(); 
		try 
		{
			Thread.sleep(10);
		} catch (InterruptedException e) 
		{
			// TODO: handle exception
		}
		t.flag = false;
		j2.start(); 
	}
}


同步函数的使用的锁是this

同步函数和同步代码块的区别:

同步函数的锁是固定的this,同步代码块的锁是任意的

所以同步时,建议使用同步代码块


验证静态同步函数的锁是什么?(了解)

静态同步函数的锁不是this,因为根本没有this

class Ticket implements Runnable
{
	private static int num = 100;
	Object god = new Object();//也可以自定义,建议使用已有的
	boolean flag = true;
	public void run()
	{
		
		if(flag==true)
		{
				while(true)
		{
			synchronized(this.getClass()) 
			//synchronized(Ticket.class)
			{
				if(num>0)
				{
					try 
					{
						Thread.sleep(10);
					} 
					catch (InterruptedException e) 
					{
						// TODO: handle exception
					}
				
	System.out.println(Thread.currentThread().getName()+"..obj.."+num--);	
			}	
			}
		}
		}
	
		else {
			while(true)
			this.show();
		}
	}
	public static synchronized void show()
	{
		if(num>0)
		{
			try 
			{
				Thread.sleep(10);
			} 
			catch (InterruptedException e) 
			{
				// TODO: handle exception
			}
		
System.out.println(Thread.currentThread().getName()+"..fu.."+num--);	
	
	}
}
}
class Main 
{
	public static void main(String[] args)
	{
		Ticket t = new Ticket();
		Thread j1 = new Thread(t);
		Thread j2 = new Thread(t);
		
		j1.start(); 
		try 
		{
			Thread.sleep(10);
		} catch (InterruptedException e) 
		{
			// TODO: handle exception
		}
		t.flag = false;
		j2.start(); 
	}
}

静态同步函数的锁 该函数所属字节码文件对象

可以使用getClass方法获取,也可以使用 当前 类名.class获取


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。