多线程——线程同步互斥(synchronized)

时间:2022-12-30 13:02:47

java中,线程互斥是为了保证在同一时刻,只有一个线程在访问一段特定的代码或者一个特定的变量。

 

看一个多线程使用同一个对象操作引起的问题:

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
package com.model.elgin.thread;

public class TestThread4 {
  
public static void main(String[] args) {
       init();
   } 

  
private static void  init(){
        
       
final PrintString ps=new PrintString();
       
//开启2个线程,分别使用同一个ps对象来打印不同的字符串
        new Thread(new Runnable() {
            
            @Override
           
public void run() {
               
while(true){    
                    ps.print(
"Chinajiangsuchangzhou");
                }
            }
        
        }).start();
        
       
new Thread(new Runnable() { 
            @Override
           
public void run() {
               
while(true){    
                    ps.print(
"Americanlalala");     
                }
            }
        }).start();
    }
}

class PrintString{
   
//按单个字符打印字符串
    public void print(String name){    
         
for (int i =0; i < name.length(); i++) { 
              System.out.print(name.charAt(i)); 
          }
          System.out.println();     
    }
}

这时候,可以从结果中偶尔发现这样的输出:

多线程——线程同步互斥(synchronized)

我们发现,2个线程中的不同的字符串内容出现了错乱,这就是在多个线程同时访问同一个资源(此处为ps对象)时出现的问题。

那么这个问题该如何处理呢?

我们可以通过对多个线程访问的公共方法或者代码块加锁来实现,保证在同一时刻只有一个线程在访问处理资源。

有2种方式来实现锁:

1)、在PrintString类的print方法上增加synchronized关键字来给方法加锁。在已有线程在调用此方法的时候,其它的线程不能调用它。

2)、通过同步代码块来给一段代码加锁,修改如下:

1
2
3
4
5
6
7
8
9
10
11
class PrintString{
   
//按单个字符打印字符串
    public void  print(String name){
      
synchronized(this){
          
for (int i =0; i < name.length(); i++) {    
               System.out.print(name.charAt(i));    
           }
           System.out.println();
       }    
    }
}

修改过后,再次运行,上述问题不再出现。

总结:

当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。即当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

注意:要互斥,必须让锁是同一把。以上的demo中,两个线程都用的是同一个new出来的ps对象,所以是同一个对象。