gpt4 book ai didi

java多线程编程之Synchronized块同步方法

转载 作者:qq735679552 更新时间:2022-09-29 22:32:09 26 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章java多线程编程之Synchronized块同步方法由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

文章分享了4个例子对synchronized的详细解释 。

1、是否加synchronized关键字的不同 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class ThreadTest {
 
   public static void main(String[] args) {
     Example example = new Example();
 
     Thread t1 = new Thread1(example);
     Thread t2 = new Thread1(example);
     t1.start();
     t2.start();
   }
}
 
class Example {
   public synchronized void excute() {
     for ( int i = 0 ; i < 5 ; ++i) {
       try {
         Thread.sleep( 1000 );
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       System.out.println( "excute:" + i);
     }
 
   }
 
}
 
class Thread1 extends Thread {
   private Example example;
 
   public Thread1(Example example) {
     this .example = example;
   }
 
   @Override
   public void run() {
     example.excute();
   }
}

加了synchronized关键字的输出结果如下 。

会先输出一组0-4,接着再输出下一组,两个线程顺序执行 。

excute:0 excute:1 excute:2 excute:3 excute:4 excute:0 excute:1 excute:2 excute:3 excute:4 。

没加synchronized关键字的输出结果如下 。

两个线程同时执行excute方法,同时并发的 。

excute:0 excute:0 excute:1 excute:1 excute:2 excute:2 excute:3 excute:3 excute:4 excute:4 。

2、多个方法的多线程情况 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class ThreadTest {
 
   public static void main(String[] args) {
     Example example = new Example();
 
     Thread t1 = new Thread1(example);
     Thread t2 = new Thread2(example);
     t1.start();
     t2.start();
   }
}
 
class Example {
   public synchronized void excute() {
     for ( int i = 0 ; i < 5 ; ++i) {
       try {
         Thread.sleep( 1000 );
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       System.out.println( "excute:" + i);
     }
   }
   public synchronized void excute1() {
     for ( int i = 0 ; i < 5 ; ++i) {
       try {
         Thread.sleep( 1000 );
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       System.out.println( "excute1:" + i);
     }
   }
 
}
 
class Thread1 extends Thread {
   private Example example;
 
   public Thread1(Example example) {
     this .example = example;
   }
 
   @Override
   public void run() {
     example.excute();
   }
}
 
class Thread2 extends Thread {
   private Example example;
 
   public Thread2(Example example) {
     this .example = example;
   }
 
   @Override
   public void run() {
     example.excute1();
   }
}

执行结果如下 。

同样是顺序执行,执行完一个线程再执行另一个线程 。

excute:0 excute:1 excute:2 excute:3 excute:4 excute1:0 excute1:1 excute1:2 excute1:3 excute1:4 。

如果去掉synchronized关键字,则两个方法并发执行,并没有相互影响.

但是如例子程序中所写,即便是两个方法:

执行结果永远是执行完一个线程的输出再执行另一个线程的。   。

说明:

  如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕前,其他线程是无法访问该对象的任何synchronized方法的.

结论:

  当synchronized关键字修饰一个方法的时候,该方法叫做同步方法.

  Java中的每个对象都有一个锁(lock),或者叫做监视器(monitor),当一个线程访问某个对象的synchronized方法时,将该对象上锁,其他任何线程都无法再去访问该对象的synchronized方法了(这里是指所有的同步方法,而不仅仅是同一个方法),直到之前的那个线程执行方法完毕后(或者是抛出了异常),才将该对象的锁释放掉,其他线程才有可能再去访问该对象的synchronized方法.

  注意这时候是给对象上锁,如果是不同的对象,则各个对象之间没有限制关系.

  尝试在代码中构造第二个线程对象时传入一个新的Example对象,则两个线程的执行之间没有什么制约关系.

3、静态的同步方法 。

当一个synchronized关键字修饰的方法同时又被static修饰,之前说过,非静态的同步方法会将对象上锁,但是静态方法不属于对象,而是属于类,它会将这个方法所在的类的Class对象上锁.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class ThreadTest {
 
   public static void main(String[] args) {
     Example example = new Example();
     Example example2 = new Example();
     Thread t1 = new Thread1(example);
     Thread t2 = new Thread2(example2);
     t1.start();
     t2.start();
   }
}
 
class Example {
   public synchronized static void excute() {
     for ( int i = 0 ; i < 5 ; ++i) {
       try {
         Thread.sleep( 1000 );
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       System.out.println( "excute:" + i);
     }
   }
   public synchronized static void excute1() {
     for ( int i = 0 ; i < 5 ; ++i) {
       try {
         Thread.sleep( 1000 );
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       System.out.println( "excute1:" + i);
     }
   }
 
}
 
class Thread1 extends Thread {
   private Example example;
 
   public Thread1(Example example) {
     this .example = example;
   }
 
   @Override
   public void run() {
     example.excute();
   }
}
 
class Thread2 extends Thread {
   private Example example;
 
   public Thread2(Example example) {
     this .example = example;
   }
 
   @Override
   public void run() {
     example.excute1();
   }
}

执行结果如下 。

excute:0 excute:1 excute:2 excute:3 excute:4 excute1:0 excute1:1 excute1:2 excute1:3 excute1:4 。

如果没有static修饰符,两个线程分别传入不同的对象,则会同时并发执行 。

所以如果是静态方法的情况(execute()和execute2()都加上static关键字),即便是向两个线程传入不同的Example对象,这两个线程仍然是互相制约的,必须先执行完一个,再执行下一个.

结论:

  如果某个synchronized方法是static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchronized方法所在的类所对应的Class对象。Java中,无论一个类有多少个对象,这些对象会对应唯一一个Class对象,因此当线程分别访问同一个类的两个对象的两个static,synchronized方法时,它们的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始.

4.synchronized块 。

synchronized(object) 。

{      。

} 。

表示线程在执行的时候会将object对象上锁。(注意这个对象可以是任意类的对象,也可以使用this关键字).

这样就可以自行规定上锁对象.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class ThreadTest {
 
   public static void main(String[] args) {
     Example example = new Example();
     Thread t1 = new Thread1(example);
     Thread t2 = new Thread2(example);
     t1.start();
     t2.start();
   }
}
 
class Example {
   public void excute() {
     synchronized ( this ) {
       for ( int i = 0 ; i < 5 ; ++i) {
         try {
           Thread.sleep( 1000 );
         } catch (InterruptedException e) {
           e.printStackTrace();
         }
         System.out.println( "excute:" + i);
       }
     }
    
   }
   public void excute1() {
     synchronized ( this ) {
       for ( int i = 0 ; i < 5 ; ++i) {
         try {
           Thread.sleep( 1000 );
         } catch (InterruptedException e) {
           e.printStackTrace();
         }
         System.out.println( "excute1:" + i);
       }
     }
    
   }
 
}
 
class Thread1 extends Thread {
   private Example example;
 
   public Thread1(Example example) {
     this .example = example;
   }
 
   @Override
   public void run() {
     example.excute();
   }
}
 
class Thread2 extends Thread {
   private Example example;
 
   public Thread2(Example example) {
     this .example = example;
   }
 
   @Override
   public void run() {
     example.excute1();
   }
}

执行结果如下 。

excute:0 excute:1 excute:2 excute:3 excute:4 excute1:0 excute1:1 excute1:2 excute1:3 excute1:4 。

例子程序4所达到的效果和例子程序2的效果一样,都是使得两个线程的执行顺序进行,而不是并发进行,当一个线程执行时,将object对象锁住,另一个线程就不能执行对应的块.

synchronized方法实际上等同于用一个synchronized块包住方法中的所有语句,然后在synchronized块的括号中传入this关键字。当然,如果是静态方法,需要锁定的则是class对象。   。

可能一个方法中只有几行代码会涉及到线程同步问题,所以synchronized块比synchronized方法更加细粒度地控制了多个线程的访问,只有synchronized块中的内容不能同时被多个线程所访问,方法中的其他语句仍然可以同时被多个线程所访问(包括synchronized块之前的和之后的).

结论:

  synchronized方法是一种粗粒度的并发控制,某一时刻,只能有一个线程执行该synchronized方法; 。

  synchronized块则是一种细粒度的并发控制,只会将块中的代码同步,位于方法内、synchronized块之外的其他代码是可以被多个线程同时访问到的.

以上就是关于java多线程编程Synchronized块同步方法,希望对大家的学习有所帮助.

最后此篇关于java多线程编程之Synchronized块同步方法的文章就讲到这里了,如果你想了解更多关于java多线程编程之Synchronized块同步方法的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com