(一)线程安全问题-线程锁(synchronized的使用)

(一)线程安全问题诱因

  • 存在有共享数据
  • 存在有多个线程访问这些共享数据

解决方法:同一时刻共享数据只能由一个线程访问,其他线程要等到该线程处理完共享数据后才能对该线程进行操作

public class Ticket{
        int ticket=0;
}

public class User implements Runnable(){
     Ticket tk;
      public User(Ticket tk){
      this.tk=tk;
      }
      public run(){
      for(int i=0;i<50;i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
				System.out.println(Thread.currentThread().getName()+"线程买了"+tk.ticket+"号票");
				tk.ticket--;
			}
		}
}



public class Test{
  Ticket tk=new Ticket();
  User user=new User();
   new Thread(user,"用户A").start();
   new Thread(user,"用户B").start();
   }

在这里插入图片描述
如图:
出现了线程错误

(二)线程锁-synchronized

线程锁的两个特性

  • 互斥性:同一时间只能有一个对象持有线程锁,通过这种特性实现多线程的协调机制。同一时间只有一个线程对需要同步的代码块进行访问,也成为原子性
  • 可见性:必须确保在锁释放之前,其对于共享变量的修改对下一个获得该锁的线程是可见的,否则另一个线程可能是在本地缓存的某个副本上进行,从而引起不一致

锁的不是代码,而是对象

1.对象锁

获取对象锁的两种方法:同步代码块同步非静态方法

同步代码块:synchronized(this),synchronized(类实例对象)
同步非静态方法:synchronized(method)

同步代码块

代码示例:

public class Ticket{
        int ticket=0;
}
public class User implements Runnable(){
     Ticket tk;
      public User(Ticket tk){
      this.tk=tk;
      }
      public run(){
      for(int i=0;i<50;i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				Synchronized(tk){                                  //**使用对象锁**
				System.out.println(Thread.currentThread().getName()+"线程买了"+tk.ticket+"号票");
				tk.ticket--;
			}
		}
}
public class Test{
  Ticket tk=new Ticket();
  User user=new User();
   new Thread(user,"用户A").start();
   new Thread(user,"用户B").start();
   }

tk即为需要访问的对象,使用synchronized来对tk对象上锁。使得同一时间只有一个User对象访问tk,而另一个User只能在锁被释放后访问。

即使用synchronized(tk)来同步代码块

此时我们可以的得到正确的访问顺序:
在这里插入图片描述
synchronized锁住的必须为同一个对象,而不能是不同的对象

同步非静态方法

方法示例:

public class Ticket{
        int ticket=0;
}

public class User implements Runnable(){
     Ticket tk;
      public User(Ticket tk){
      this.tk=tk;
      }
      public run(){
      for(int i=0;i<50;i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			ticket();				
			}
		}
	public synchronized void ticket(){                    //**同步非静态方法**
	  System.out.println(Thread.currentThread().getName()+"购买了"+tk.ticket+"号票");
	  tk.ticket--;
}   



public class Test{
  Ticket tk=new Ticket();
  User user=new User();
   new Thread(user,"用户A").start();
   new Thread(user,"用户B").start();
   }
 

同样使用public synchronized void ticket()同步非静态方法也可以实现线程锁

2.类锁

同步代码块(synchronized (类Class) )

代码示例:

public class User implements Runnable(){
     Ticket tk;
      public User(Ticket tk){
      this.tk=tk;
      }
      public run(){
      for(int i=0;i<50;i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				Synchronized(Ticket.class){                                  //**使用类锁**
				System.out.println(Thread.currentThread().getName()+"线程买了"+tk.ticket+"号票");
				tk.ticket--;
			}
		}
}

即对于Ticketk类整体使用类锁

synchronized(Ticket.class){
}

类锁可以使同一时间只有一个线程持有此类锁

同步静态方法(synchronized static method)

代码示例:

public class Ticket{
        static int ticket=0;
        public synchronized static void ticket(){              //同步静态方法
          System.out.println(Thread.currentThread().getName()+"线程买了"+tk.ticket+"号票");
				tk.ticket--;
		 } 
}

public class User implements Runnable(){
     Ticket tk;
      public User(Ticket tk){
      this.tk=tk;
      }
      public run(){
      for(int i=0;i<50;i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
				tk.ticket();
			}
		}
}



public class Test{
  Ticket tk=new Ticket();
  User user=new User();
   new Thread(user,"用户A").start();
   new Thread(user,"用户B").start();
   }

即对Ticket类中的静态方法进行同步
public synchronized static void method()

(三)对象锁与类锁的总结

  • 线程访问该对象的同步代码块时,其他线程可以访问该线程的非同步代码块
  • 若锁住的是对象,则当一个线程访问该对象的同步代码块(非静态方法),其它线程不能访问这个对象的同步代码块(非静态方法)
  • 若锁住的是对象,则当一个线程访问该对象的同步代码块(非静态方法),其它线程不能访问这个对象的非静态方法(同步代码块)
  • 若锁住的是类,则当一个线程访问该类的同步代码块(静态方法),其它线程不能访问这个类的同步代码块(静态方法)
  • 若锁住的是类,则当一个线程访问该类的同步代码块(静态方法),其它线程不能访问这个类的静态方法(同步代码块)
  • 同一个类不同的对象锁互不干扰
  • 类锁和对象锁互不干扰
  • 同一个类的不同对象使用类锁是也会同步
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值