java资源锁synchronized说“给我一把 锁,我能创造一个规矩”

在java多线程编程中,我们需要对java对象中的资源进行同步管理,确保在同一时刻,只能由同一线程访问类或者对象中的资源,这样可以防止由于几个线程共享同一资源导致不可知的后果。

方法之一就是利用资源锁(synchronized),废话少说,先上例子

例子一

public class S_1 {
 public static void main(String[] args) {
  for(int i=0;i<5;i++){
   new Thread_1().start();
  }
 }
}

class Thread_1 extends Thread{
 @Override
 public synchronized void run() {
  for(int i=0;i<100;i++){
   System.out.println(i);
  }
 }
 
}

例子二:

public class S_2 {
 public static void main(String[] args) {
  for(int i=0;i<5;i++){
   new Thread_2().start();
  }
 }
}
class Thread_2 extends Thread{
 @Override
 public void run(){
  synchronized(this){
   for(int i=0;i<100;i++){
    System.out.println(i);
   }
  }
 }
}

例子三:


public class S3 {
 public static void main(String[] args) {
  for(int i=0;i<5;i++){
   new Thread_3().start();
  }
 }
}
class Thread_3 extends Thread{
 public synchronized static void show(){
  for(int i=0;i<100;i++){
   System.out.println(i);
  }
 }
 @Override
 public void run(){
  show();
 }

}

例子四:

public class S_4 {
 public static void main(String[] args) {
  for(int i=0;i<5;i++){
   String lock = "lock";
   new Thread_4(lock).start();
  }
 }
}
class Thread_4 extends Thread{
 private String lock ;
 public Thread_4(String lock){
  this.lock = lock ;
 }
 @Override
 public void run(){
  synchronized(lock){
   for(int i=0;i<100;i++){
    System.out.println(i);
   }
  }
 }
 
}
以上四个例子是用五个线程从0-99进行打印,他们都是按照先后顺序从0-99进行打印的吗?如果你的答案是按顺序依次打印的话,那你就错了,下边我一一来讲解下

例子一,没有按照先后顺序进行打印。我们对run方法进行了加锁,按理说是该按照先后顺序进行打印的,但是为什么结果与我们想象的不一样呢?由于我们起五个线程的时候,我们创建了五个Thread_1对象,这样每个线程都获取了一个对象,每个线程都获取了自己对象中run方法的锁,所以,这里的资源锁是没有意义的,如果要让这里的锁起作用,除非该Thread_1是单例模式的,这样这些线程都共享一个对象,才会按照先后顺序获取锁

例子二,没有按照先后顺序进行打印。我们对run方法中的一部分代码进行了synchronized块保护,也应该按照每个线程依次打印,但为什么还是没有依次打印呢?由于我们synchronized(this)中的this在五个线程中是没有共享的,五个线程中的this都不一样,这样相当于对五个对象进行资源块进行保护,五个线程依然能够同时获取synchronized(this)方法中的代码执行的锁

例子三,按照先后顺序打印。这个例子可以和例子一对应起来看,我们是在show方法上加的锁,并且show方法是static的,这样这里方法就是类方法,被所以对象共享的,当我们起五个线程,这五个线程对show方法是共享的,而且该方法被加锁了,当线程来访问的时候,首先看这个方法是否被其他线程使用,如果正在被其他对象使用,对不起,你先等着,等下一个线程用完了,退出了的时候,线程池中轮到你的时候,你才能执行该方法

例子四,按照先后顺序打印。这个例子可以和例子四对应起来看,首先我们来看下例子4,类Thread_4是一个继承Thread的线程类,他有一个私有变量lock,在其run方法中,我们用锁块对要打印的语句进行保护,我们在启动线程的时候,通过构造方法,给Thread_4的lock变量进行赋值,由于我们启动的五个线程中,每个Thread对象的lock变量的值都是同一个,即五个线程共享变量lock,所以要执行被synchronized方法锁起来的语句,也必须获得相应的锁才能够执行,对比例子一种,this的值在每个线程中不一样的

 

最后总结

如果我们想通过synchronized来修辞方法,来达到在同一时刻,该方法只能被同一线程访问的话,有两个条件

条件一:线程对象是一个单例类

条件二:synchronized修饰的方法是static的

如果我们想通过synchronized方法来达到在同一时刻,被保护的语句块只能被同一线程访问,其条件是

synchronized方法中传入的对象必须是共享的,即传入的对象必须是一样的

 

希望这篇博文对你有用,如果我对synchronized认识不到位的地方,请多多指教

 

 

 

    

 

 

你可能感兴趣的:(java,多线程,synchronized,java多线程)