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();
        }
    }
}
原文地址:https://www.cnblogs.com/viplanyue/p/12700525.html