• java多线程--多线程同步


    为何要实现同步

      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  }

    运行结果:

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

    同步方法

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

    具体语法格式:

      

     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  }

    运行结果:

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

     
  • 相关阅读:
    IIS10中使用OpenSSL来创建CA并且签发SSL证书
    vim简单题练习-------出自《鸟哥的linux私房菜》第309页码题目
    Linux删除命令rm
    CentOS下Vim加密解密文本
    Linux中bash shell环境变量
    Linux文件系统损坏导致无法正常启动与fsck修复工具
    rm -rf /*时遇到的趣事
    Linux中tree无法正常显示中文的解决方法
    执行shell脚本的四种方式
    私有网络(VPC)概述
  • 原文地址:https://www.cnblogs.com/wx60079/p/13297948.html
Copyright © 2020-2023  润新知