java多线程对象锁 类锁 同步机制详解

分享一下我老师大神的人工智能教程吧。零基础,通俗易懂!风趣幽默!http://www.captainbed.net/

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

1.在java多线程编程中对象锁、类锁、同步机制synchronized详解:

    对象锁:在java中每个对象都有一个唯一的锁,对象锁用于对象实例方法或者一个对象实例上面的。

    类锁:是用于一个类静态方法或者class对象的,一个类的实例对象可以有多个,但是只有一个class对象。

    同步机制synchronizedsynchronized关键字用于修饰方法或者单独的synchronized代码块,当一个线程想执行synchronized中的内容时,必须先获取到对象锁,当对象锁没有线程占用时,进入synchronized方法会自动获取到对象锁,执行完毕后会自动释放锁,如果对象锁被A线程占用,B线程想执行synchronized的代码只能等待A个线程执行完毕后,释放对象锁,B线程才能获取到对象锁进入方法执行。一个线程获得对象A的锁,也可以获得对象B的锁,两个不同类的对象锁没有关联。

举例说明包含synchronized的方法和synchronized代码块

package com.test;public class TestThread public void test1() {  synchronized (this) {   int i = 0;   while (i++<5) {    System.out.println(Thread.currentThread().getName() + " : " + i);    try {     Thread.sleep(500);    } catch (InterruptedException ie) {    }   }  } } public synchronized void test2() {  int i = 0;    while (i++<5) {   System.out.println(Thread.currentThread().getName() + " : " + i);   try {    Thread.sleep(500);   } catch (InterruptedException ie) {   }  } } public static void main(String[] args) {  final TestThread test = new TestThread();  Thread test1 = new Thread(new Runnable() {   public void run() {    test.test1();   }  }, "test1");  Thread test2 = new Thread(new Runnable() {   public void run() {    test.test2();   }  }, "test2");  test1.start();  test2.start(); }}


以上代码执行结果如下:

以上代码是因为执行同一个对象,所以另一个线程要等前一个对象,执行完成后释放掉对象锁,拿到对象锁才能继续执行synchronized里面的东西。

如果我们去掉synchronized修饰的方法或者synchronized代码块,将会打印出以下的结果:


如何要是去掉一个synchronized后,输出的语句是交叉执行的。这就说明,对于同一个对象,如果线程A得到了对象锁,线程B可以访问对象没有同步的方法和代码。进行同步的代码和没有同步的代码是互不影响的。

举例类锁:

package com.test;public class MyThreadClass public static void main(String[] args) {  final MyThreadClass my=new MyThreadClass();  Thread thread1=new Thread(new Runnable() {   @Override   public void run() {    try {     my.test1();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test1");  Thread thread2=new Thread(new Runnable() {   @Override   public void run() {    try {     MyThreadClass.test2();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test2");  thread1.start();  thread2.start(); }   public void test1() throws InterruptedException{  synchronized (MyThreadClass.class) {   int i=0;   while(i++<5){    System.out.println(Thread.currentThread().getName()+":"+i);    Thread.sleep(500);   }  } }  public static synchronized void test2() throws InterruptedException{   int i=0;   while(i++<5){    System.out.println(Thread.currentThread().getName()+":"+i);    Thread.sleep(500);   } }} 
执行结果:



类锁和对象锁其实是一样的,只是针对于不同的对象。

如果两个方法一个被synchronized修饰,一个静态方法被synchronized修饰(体现类锁和对象锁的区别),代码如下:

package com.test;public class MyThreadClass2 public static void main(String[] args) {  final MyThreadClass2 my=new MyThreadClass2();  Thread thread1=new Thread(new Runnable() {   @Override   public void run() {    try {     my.test1();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test1");  Thread thread2=new Thread(new Runnable() {   @Override   public void run() {    try {     MyThreadClass2.test2();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test2");  thread1.start();  thread2.start(); }  public synchronized void test1() throws InterruptedException{   int i=0;   while(i++<5){    System.out.println(Thread.currentThread().getName()+":"+i);    Thread.sleep(500);   } }  public static synchronized void test2() throws InterruptedException{   int i=0;   while(i++<5){    System.out.println(Thread.currentThread().getName()+":"+i);    Thread.sleep(500);   } }} 
代码执行结果如下:


结果也是交叉输出的,虽然都是被synchronized修饰,但是一个是属于对象的,一个是属于class。所以类锁和对象锁是不同的,他们控制着不同的区域,互不干扰。

疑问:java中既然synchronized修饰的方法和synchronized代码块作用是一样的,为什么还需要synchronized代码块呢?

使用synchronized修饰方式是直接在方法上面加锁,synchronized方法块是在方法里面加锁,一个范围大,一个范围小。还有一个最主要的在应用场景如下:在Class中创建一个对象,在Class中要执行这个对象的某个方法,为了防止多个线程同时执行,采用同步加锁,但是如果这个方法出现死循环或者执行时间很长,其他线程也不能执行对象的其他同步方法,需要等待这个线程执行完毕,影响系统性能。如果采用synchronized修饰方法和synchronized代码块可能都会出现这种情况,我们来模拟一下这种状况:

创建一个java对象类,里面有两个方法:

package com.test;public class Test public void test1(){ } public void test2(){ }}
创建测试类代码如下:

package com.test;public class MyThreadClass4 static Test test=new Test(); public static void main(String[] args) {  final MyThreadClass4 my=new MyThreadClass4();  Thread thread1=new Thread(new Runnable() {   @Override   public void run() {    try {     my.test1();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test1");  Thread thread2=new Thread(new Runnable() {   @Override   public void run() {    try {     my.test2();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test2");  thread1.start();  thread2.start(); } long startTime; public synchronized void test1() throws InterruptedException{   test.test1();   System.out.println(Thread.currentThread().getName());   startTime = System.currentTimeMillis();//获取当前时间   Thread.sleep(5000); }  public synchronized void test2() throws InterruptedException{  long endTime = System.currentTimeMillis();  test.test2();  System.out.println(Thread.currentThread().getName());  System.out.println("程序运行时间:"+(endTime-startTime)+"ms"); }} 

在class里面创建对象实例,然后将两个方法分别调用,在调用方法上面都加上synchronized修饰方法Thread.sleep(5000)来模拟方法执行时间过长或者死循环,但是可以看到时间为我们设置的时间,执行结果不理想执行结果如下:


如果我们采用synchronized代码块的方式如下:

package com.test;public class MyThreadClass3 static Test test=new Test(); public static void main(String[] args) {  final MyThreadClass3 my=new MyThreadClass3();  Thread thread1=new Thread(new Runnable() {   @Override   public void run() {    try {     my.test1();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test1");  Thread thread2=new Thread(new Runnable() {   @Override   public void run() {    try {     my.test2();    } catch (InterruptedException e) {     e.printStackTrace();    }   }  },"test2");  thread1.start();  thread2.start(); } long startTime; public void test1() throws InterruptedException{  synchronized (test) {   test.test1();   System.out.println(Thread.currentThread().getName());   startTime = System.currentTimeMillis();//获取当前时间   Thread.sleep(5000);  } }  public synchronized void test2() throws InterruptedException{  long endTime = System.currentTimeMillis();  test.test2();  System.out.println(Thread.currentThread().getName());  System.out.println("程序运行时间:"+(endTime-startTime)+"ms"); }} 
synchronized代码块中我们只是对当前test对象加锁,和执行这块代码的对象没有任何关系。执行test1的同时,我照样可以执行其他的synchronized同步方法,增强系统性能。执行结果如下:

           

给我老师的人工智能教程打call!http://www.captainbed.net/

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_43717814/article/details/84293482