JAVA自学教程之线程的同步问题



JAVA自学教程之线程的同步。

继续以卖票为例

 

一、线程安全问题的解决

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

 

思路:

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

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

同步代码块格式:

synchronized(对象)

{

需要被同步的代码部分

}

  1. class Ticket implements Runnable
  2. {
  3.     private int num = 100;
  4.     Object god = new Object();//也可以自定义,建议使用已有的
  5.     public void run()
  6.     {
  7.         while(true)
  8.         {
  9.             synchronized(god) //同步
  10.             {
  11.                 if(num>0)
  12.                 {
  13.                     try
  14.                     {
  15.                         Thread.sleep(10);
  16.                     }
  17.                     catch (InterruptedException e)
  18.                     {
  19.                         // TODO: handle exception
  20.                     }
  21.     System.out.println(Thread.currentThread().getName()+”..sale..”+num–);
  22.             }
  23.             }
  24.         }
  25.     }
  26. }
  27. public class Main
  28. {
  29.     public static void main(String[] args)
  30.     {
  31.         Ticket t = new Ticket();
  32.         Thread j1 = new Thread(t);
  33.         Thread j2 = new Thread(t);
  34.         Thread j3 = new Thread(t);
  35.         Thread j4 = new Thread(t);
  36.         j1.start(); j2.start();
  37.         j3.start(); j4.start();
  38.     }
  39. }
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时,释放执行权,执行权会给其他线程,然后进行判断同步锁,判断完又进不去,所以相对以前会降低效率,是在可承受的范围内

 

二、同步的前提


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

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

 

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

 

  1. /*
  2. * 需求:
  3. * 两个人到银行存钱,每次存10,每个人都是三次
  4. *
  5. * */
  6. class Bank
  7. {
  8.     private int sum;
  9.     private Object obj = new Object();
  10.     //同步代码代码块表现形式
  11.     /*public void add(int num)
  12.     {
  13.         synchronized(obj)
  14.         {
  15.             sum += num;
  16.         try {
  17.             Thread.sleep(10);
  18.         } catch (InterruptedException e) {
  19.             // TODO: handle exception
  20.         }
  21.         System.out.println(“sum = “+sum);
  22.         }
  23.     }*/
  24.     //同步函数表现形式
  25.     public synchronized void add(int num)
  26.     {
  27.         sum += num;
  28.         try {
  29.             Thread.sleep(10);
  30.         } catch (InterruptedException e) {
  31.             // TODO: handle exception
  32.         }
  33.         System.out.println(“sum = “+sum);
  34.     }
  35. }
  36. class Custom implements Runnable
  37. {
  38.     private Bank bank = new Bank();
  39.     public void run()
  40.     {
  41.         for(int i = 0;i<3;i++)
  42.         {
  43.             bank.add(10);
  44.         }
  45.     }
  46. }
  47. class Main
  48. {
  49.     public static void main(String[] args)
  50.     {
  51.         Custom tCustom = new Custom();
  52.         Thread j1 = new Thread(tCustom);
  53.         Thread j2 = new Thread(tCustom);
  54.         j1.start();
  55.         j2.start();
  56.     }
  57. }
/*
 * 需求:
 * 两个人到银行存钱,每次存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();
	}
}

 

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

  1. class Ticket implements Runnable
  2. {
  3.     private int num = 100;
  4.     Object god = new Object();//也可以自定义,建议使用已有的
  5.     boolean flag = true;
  6.     public void run()
  7.     {
  8.         if(flag==true)
  9.         {
  10.                 while(true)
  11.         {
  12.             synchronized(this) //同步
  13.             {
  14.                 if(num>0)
  15.                 {
  16.                     try
  17.                     {
  18.                         Thread.sleep(10);
  19.                     }
  20.                     catch (InterruptedException e)
  21.                     {
  22.                         // TODO: handle exception
  23.                     }
  24.     System.out.println(Thread.currentThread().getName()+”..obj..”+num–);
  25.             }
  26.             }
  27.         }
  28.         }
  29.         else {
  30.             while(true)
  31.             this.show();
  32.         }
  33.     }
  34.     public synchronized void show()
  35.     {
  36.         if(num>0)
  37.         {
  38.             try
  39.             {
  40.                 Thread.sleep(10);
  41.             }
  42.             catch (InterruptedException e)
  43.             {
  44.                 // TODO: handle exception
  45.             }
  46. System.out.println(Thread.currentThread().getName()+”..fu..”+num–);
  47.     }
  48. }
  49. }
  50. class Main
  51. {
  52.     public static void main(String[] args)
  53.     {
  54.         Ticket t = new Ticket();
  55.         Thread j1 = new Thread(t);
  56.         Thread j2 = new Thread(t);
  57.         j1.start();
  58.         try
  59.         {
  60.             Thread.sleep(10);
  61.         } catch (InterruptedException e)
  62.         {
  63.             // TODO: handle exception
  64.         }
  65.         t.flag = false;
  66.         j2.start();
  67.     }
  68. }
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

  1. class Ticket implements Runnable
  2. {
  3.     private static int num = 100;
  4.     Object god = new Object();//也可以自定义,建议使用已有的
  5.     boolean flag = true;
  6.     public void run()
  7.     {
  8.         if(flag==true)
  9.         {
  10.                 while(true)
  11.         {
  12.             synchronized(this.getClass())
  13.             //synchronized(Ticket.class)
  14.             {
  15.                 if(num>0)
  16.                 {
  17.                     try
  18.                     {
  19.                         Thread.sleep(10);
  20.                     }
  21.                     catch (InterruptedException e)
  22.                     {
  23.                         // TODO: handle exception
  24.                     }
  25.     System.out.println(Thread.currentThread().getName()+”..obj..”+num–);
  26.             }
  27.             }
  28.         }
  29.         }
  30.         else {
  31.             while(true)
  32.             this.show();
  33.         }
  34.     }
  35.     public static synchronized void show()
  36.     {
  37.         if(num>0)
  38.         {
  39.             try
  40.             {
  41.                 Thread.sleep(10);
  42.             }
  43.             catch (InterruptedException e)
  44.             {
  45.                 // TODO: handle exception
  46.             }
  47. System.out.println(Thread.currentThread().getName()+”..fu..”+num–);
  48.     }
  49. }
  50. }
  51. class Main
  52. {
  53.     public static void main(String[] args)
  54.     {
  55.         Ticket t = new Ticket();
  56.         Thread j1 = new Thread(t);
  57.         Thread j2 = new Thread(t);
  58.         j1.start();
  59.         try
  60.         {
  61.             Thread.sleep(10);
  62.         } catch (InterruptedException e)
  63.         {
  64.             // TODO: handle exception
  65.         }
  66.         t.flag = false;
  67.         j2.start();
  68.     }
  69. }
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获取