• Java第二十四天,线程安全


    线程安全

    1.定义

    多线程访问共享数据,会产生线程安全问题。

    2.代码模拟

    卖票Ticked类:

    package com.lanyue.day22;
    
    public class Person {
    
        public static void main(String[] args) {
    
            Car one = new Car("宝马");
    
            one.start();
    
            Driver two = new Driver();
            new Thread(two).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i = 0;i < 5;i++){
    
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("第二个司机第" + i + "次报数中。");
                    }
                }
            }).start();
        }
    }
    

    卖票窗口Window类

    package com.lanyue.day23;
    
    public class Windows {
    
        public static void main(String[] args) {
    
            Ticked runnable = new Ticked();
            Thread one = new Thread(runnable);
            Thread two = new Thread(runnable);
            Thread three = new Thread(runnable);
    
            one.start();
            two.start();
            three.start();
        }
    }
    

    程序执行图

    3.解决方法

    当使用多个线程对同一个资源有写操作时,就容易出现线程安全问题。为解决这个问题,Java提供了同步机制synchronized来解决这个问题。

    那么如何实现所谓的同步机制呢?有三个方法:

    1.同步代码块

    synchronized用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

    示例:

    synchronized (同步锁){
        //代码块.
    }

    注意:

    (1)同步代码块中的锁对象可以是任意对象。

    (2)必须保证多个线程使用的锁对象是同一个对象。

    示例代码:

    package com.lanyue.day23;
    
    public class Ticked implements Runnable {
    
        public Integer ticks = 100;
        public Object obj = new Object();
        public boolean state = true;
    
        @Override
        public void run() {
    
            while(state){
    
                synchronized (obj){
    
                    if(ticks-- > 0){
    
                        System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票");
    
                    }else{
    
                        state = false;
                    }
                }
            }
        }
    }
    

     

    2.同步方法

    (1)普通同步锁方法:

    只需要在方法前加一个修饰符 synchronized 即可(本质上也是利用锁对象锁定的,这个锁是this)。

    格式:

    权限修饰符 synchronized 返回值类型 方法名(参数){

    方//法体

    示例代码:

    package com.lanyue.day23;
    
    public class TickedTwo implements Runnable{
    
        public Integer ticks = 100;
        public boolean state = true;
    
        @Override
        public void run(){
    
            while(state){
    
                view();
            }
        }
    
        public synchronized void view(){
    
            if(ticks-- > 0){
    
                System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票");
    
            }else{
    
                state = false;
            }
        }
    }
    

    (3)静态同步方法

    本质也是利用锁对象,这个锁对象是class文件对象

    格式:

    权限修饰符 static synchronized 返回值类型 方法名(参数){

    //方法体。

    示例代码:

    package com.lanyue.day23;
    
    public class TickedThree implements Runnable{
    
        public static Integer ticks = 100;
        public static boolean state = true;
    
        @Override
        public void run() {
    
            while(state){
    
                view();
            }
        }
    
        public static synchronized void view(){
    
            if(ticks-- > 0){
    
                System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票");
    
            }else{
    
                state = false;
            }
        }
    }
    

    3.锁机制

    Lock接口

    ReentrantLock类是Lock接口的实现类。

    使用步骤:

    (1)在成员变量位置创建 ReentrantLock 对象。

    (2)在可能发生线程安全问题的代码前调用ReentrantLock 对象的lock()方法锁住共享数据。

    (3)在可能发生线程安全问题的代码后调用ReentrantLock  对象的unlock()方法解锁共享资源。

    代码示例:

    package com.lanyue.day23;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    public class TickedFour implements Runnable {
    
        public ReentrantLock myLock = new ReentrantLock();
        public Integer ticks = 100;
        public boolean state = true;
    
        @Override
        public void run() {
    
            while(state){
    
                myLock.lock();
                if(ticks-- > 0){
    
                    System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票");
    
                }else{
    
                    state = false;
                }
    
                myLock.unlock();
            }
        }
    }
    
  • 相关阅读:
    操作系统开发系列—13.g.操作系统的系统调用 ●
    操作系统开发系列—13.f.Minix的中断处理(暂时忽略)
    操作系统开发系列—13.e.三进程
    操作系统开发系列—13.d.多进程 ●
    操作系统开发系列—解释typedef void (*int_handler) ();
    操作系统开发系列—13.c.进程之中断重入
    操作系统开发系列—13.b.进程之丰富中断处理程序
    操作系统开发系列—13.a.进程 ●
    操作系统开发系列—12.g.在内核中设置键盘中断
    操作系统开发系列—12.f.在内核中添加中断处理 ●
  • 原文地址:https://www.cnblogs.com/viplanyue/p/12700525.html
Copyright © 2020-2023  润新知