为何要实现同步

 java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),      将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。

 同步代码块

即有synchronized关键字修饰的语句块。 

    被该关键字修饰的语句块会自动被加上内置锁,从而实现同步 

    代码如: 

synchronized(lock){ 
  操作共享资源代码块
    }

  上面的代码中,lock是一个锁对象,它是同步代码块的关键,保证用于处理共享资源的代码在任何时刻只能有一个线程访问

     注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 

    通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。

1 @SpringBootTest
 2 //Ticket,实现Runnable接口
 3 class Ticket implements Runnable{
 4     //定义变量tickets,并赋值10
 5     private int tickets = 10;
 6     //定义任意一个对象,用作同步代码块的锁
 7     Object lock = new Object();
 8 
 9     //实现接口中的run()方法
10     @Override
11     public void run() {
12        while (true){
13            synchronized (lock){
14                try {
15                    Thread.sleep(10);
16                }catch (InterruptedException e){
17                    e.printStackTrace();
18                }
19                if (tickets > 0){
20                    System.out.println(Thread.currentThread().getName() + "---卖出的票" + tickets--);
21                }else {
22                    //如果tickets 小于0 ,跳出循环
23                    break;
24                }
25            }
26        }
27     }
28 }
29 public class Example {
30     public static void main(String[] args) {
31         //创建Ticket对象
32         Ticket ticket = new Ticket();
33         //开启四个线程
34         new Thread(ticket,"线程一").start();
35         new Thread(ticket,"线程二").start();
36         new Thread(ticket,"线程三").start();
37         new Thread(ticket,"线程四").start();
38     }
39  }

运行结果:

java多线程同步互斥 java多线程并发同步_同步方法

 

将有关tickets变量的操作全部都放到同步代码块中,为了保证线程的持续执行,将同步代码块放在死循环中,直到tickets<0时跳出循环,持续在获得锁对象时有一定的随机性,在整个程序的运行期间,线程二和线程三始终未获得锁对象。

同步方法

 在方法面前同样可以使用synchronized关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能。

具体语法格式:

    synchronized 返回值类型 方法名([参数1,*****]){}

 

1 @SpringBootTest
 2 //Ticket,实现Runnable接口
 3 class Ticket implements Runnable{
 4     //定义变量tickets,并赋值10
 5     private int tickets = 10;
 6 
 7     //实现接口中的run()方法
 8     public void run() {
 9        while (true){
10            saleTicket(); //调用售票方法
11            if (tickets <=0){
12                break;
13            }
14        }
15 
16     }
17     //定义一个同步方法saleTicket
18     private synchronized void saleTicket(){
19         if (tickets > 0){
20             try {
21                 Thread.sleep(100);
22             }catch (InterruptedException e){
23                 e.printStackTrace();
24             }
25             System.out.println(Thread.currentThread().getName() + "卖出的票 --" + tickets --);
26         }
27     }
28 }
29 public class Example {
30     public static void main(String[] args) {
31         //创建Ticket对象
32         Ticket ticket = new Ticket();
33         //开启四个线程
34         new Thread(ticket,"线程一").start();
35         new Thread(ticket,"线程二").start();
36         new Thread(ticket,"线程三").start();
37         new Thread(ticket,"线程四").start();
38     }
39  }

运行结果:

java多线程同步互斥 java多线程并发同步_跳出循环_02

 

 将售票代码抽取为售票方法saleTicket(),并用synchronized关键字把saleTicket()修饰为同步方法,实现了和同步代码块一样的效果。