• java中多线程安全性和同步的常用方法


    1、多线程安全性问题,即多线程在什么场景下会出现异常?

    多个线程同时调用一个共享的变量(对象),比如当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。

    2、在Java中,我们通过同步机制,来解决线程的安全问题。

    3、有几种同步机制?

    有3种,同步代码块、同步方法、Lock;

    4、同步代码块

     代码如下:

    synchronized(同步监视器){
         //需要被同步的代码
     }

    注意:

    (1)同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。要求:多个线程必须要共用同一把锁。同步监视器必须唯一,且是一个对象。也就是多个线程共享一个同步监视器对象。否则同步代码块不生效。

     (2)包裹的代码是操作共享数据的代码,即为需要被同步的代码。不能多,也不能少,否则就会出错。

    (3)共享数据:多个线程共同操作的变量。

     (4)在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。

    (5)在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器。也就是"类名.class",比如“Student.class”。

    实例代码1(实现Runnable接口):

    class Window1 implements Runnable{
    
        private int ticket = 100;
    //    Object obj = new Object();
    //    Dog dog = new Dog();
        @Override
        public void run() {
    //        Object obj = new Object();
            while(true){
                synchronized (this){//此时的this:唯一的Window1的对象   //方式二:synchronized (dog) {
    
                    if (ticket > 0) {
    
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                        System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
    
    
                        ticket--;
                    } else {
                        break;
                    }
                }
            }
        }
    }
    View Code

    实例代码2(继承Thread):

    class Window2 extends Thread{
    
    
        private static int ticket = 100;
    
        private static Object obj = new Object();
    
        @Override
        public void run() {
    
            while(true){
                //正确的
    //            synchronized (obj){
                synchronized (Window2.class){//Class clazz = Window2.class,Window2.class只会加载一次
                    //错误的方式:this代表着t1,t2,t3三个对象
    //              synchronized (this){
    
                    if(ticket > 0){
    
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                        System.out.println(getName() + ":卖票,票号为:" + ticket);
                        ticket--;
                    }else{
                        break;
                    }
                }
    
            }
    
        }
    }
    View Code

    5、同步方法

    (1)同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。

    (2)非静态的同步方法,同步监视器是:this
      静态的同步方法,同步监视器是:当前类本身

    实例代码1(实现Runnable接口)

    class Window3 implements Runnable {
    
        private int ticket = 100;
    
        @Override
        public void run() {
            while (true) {
    
                show();
            }
        }
    
        private synchronized void show(){//同步监视器:this
            //synchronized (this){
    
                if (ticket > 0) {
    
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
    
                    ticket--;
                }
            //}
        }
    }
    View Code

    实例代码2(继承Thread)

    class Window4 extends Thread {
    
    
        private static int ticket = 100;
    
        @Override
        public void run() {
    
            while (true) {
    
                show();
            }
    
        }
        private static synchronized void show(){//同步监视器:Window4.class
            //private synchronized void show(){ //同步监视器:t1,t2,t3。此种解决方式是错误的
            if (ticket > 0) {
    
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                ticket--;
            }
        }
    }
    View Code

    6、单例模式中懒汉模式的线程安全的代码:

    lass Bank{
    
        private Bank(){}
    
        private static Bank instance = null;
    
        public static Bank getInstance(){
            //方式一:效率稍差
    //        synchronized (Bank.class) {
    //            if(instance == null){
    //
    //                instance = new Bank();
    //            }
    //            return instance;
    //        }
            //方式二:效率更高
            if(instance == null){
    
                synchronized (Bank.class) {
                    if(instance == null){
    
                        instance = new Bank();
                    }
    
                }
            }
            return instance;
        }
    
    }
    View Code
  • 相关阅读:
    H3C Comware V5、V7平台交换机分类
    如何从症状上区别风寒感冒与过敏性鼻炎
    rdp3389mstsc使用剪贴板重定向通过远程桌面服务或终端服务会话复制大于 2 GB 的文件 (复制) 会以静默方式失败
    小区光纤PON接入组网方式与案例
    Esxi6.7网络trunk端口设置和vlan端口设置访问
    安装VCenter 6.7的系统要求
    win10自定义时间服务器
    fabric基础设施管理-(四)多机-动态新增组织节点
    fabric基础设施管理-(三)单机-动态新增组织节点
    fabric基础设施管理-(二)基础网络搭建
  • 原文地址:https://www.cnblogs.com/puzi0315/p/16142718.html
Copyright © 2020-2023  润新知