多线程实现同步机制

  时间:2020-07-14 11:20:32  阅读量:607  评论数:0  作者:程序大西瓜

该文着重介绍多线程实现同步机制相关知识,作者举例代码和分析说明恰到好处,遇到问题的朋友可以研究一下。

Synchronized

注意:1)同步一定要同步不变的东西,会变的锁不住,对象地址肯定不会变
           2)遇到死锁时会自动解锁
同步方法:简单,效率低,可以同步成员方法和静态方法

public class AccountRunnable implements Runnable{
    private Account account=new Account();
    @Override
    public void run() {
        withdraw();
    }

    private synchronized void withdraw() {
        if (account.getYuE() >= 400) {//600
            try {
                Thread.sleep(1);//出让CPU执行权
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //取钱
            account.withDraw(400);//200 -400 =-200
            System.out.println(Thread.currentThread().getName()   "取钱成功,余额是:"   account.getYuE());
        } else {
            //余额不足通知用户 不能取钱
            System.out.println(Thread.currentThread().getName()   "取钱失败,余额是:"   account.getYuE());
        }
    }
}

同步代码块:synchronized(this|类.class| 资源(成员属性)){ }

public class AccountRunnable implements Runnable{
    private Account account=new Account();
    @Override
    public void run() {
        synchronized (account){
            if (account.getYuE() >= 400) {//600
                try {
                    Thread.sleep(1);//出让CPU执行权
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //取钱
                account.withDraw(400);//200 -400 =-200
                System.out.println(Thread.currentThread().getName()   "取钱成功,余额是:"   account.getYuE());
            } else {
                //余额不足通知用户 不能取钱
                System.out.println(Thread.currentThread().getName()   "取钱失败,余额是:"   account.getYuE());
            }
        }
    }
}

Lock重入锁

注意:1)使用重入锁时要先创建锁,Lock lock=new ReentrantLock();
           2)需要我们自己手动上锁;(lock.lock())和手动开锁(lock.unLock()),当线程出现死锁时不会自动解锁,一定要手动解锁;
           3)当需要两个及以上的锁时需要:Condition con1=lock.newCondition();
           4)在lock.lock()和lock.unLock()当中使用con1.await()使得当前线程进入等待队列中,让出CPU,con1.signal()唤醒等待的线程

public class ProductFactory {
    //定义集合 存储商品

    ArrayList<String> list = new ArrayList<>();

    //库存商品最大为10
    int max = 10;

    private Lock lock=new ReentrantLock();

    Condition produceLock=lock.newCondition();
    Condition consumerLock=lock.newCondition();
    //生产商品
    public  void produce(String name) throws InterruptedException {
        lock.lock();
        try {
            //当库存满不再添加
            //此时是多条线程  循环的去校验 是否已满
            while (list.size()==max){
                produceLock.await();
            }
            //将商品添加到集合内
            list.add(name);
            //输出信息
            System.out.println(Thread.currentThread().getName()   "生产了商品:"   name "商品的库存是:" list.size());
            //通知消费者进行消费
            consumerLock.signal();
        } finally {
            lock.unlock();
        }

    }

    //消费商品
    public  void commu() throws InterruptedException {
        lock.lock();
        try {
            //当没有商品时 进行等待
            while (list.size() == 0) {
                consumerLock.await();
            }
            //移除一个商品
            String name = list.remove(0);
            System.out.println(Thread.currentThread().getName()   "消费者消费了:"   name "商品的库存是:" list.size());
            //通知生产者进行生产
            produceLock.signal();
        } finally {
            lock.unlock();
        }

    }
}

Volatile关键词

一种轻量级的同步策略,当多个线程进行操作共享数据时,可以保证内存中的数据可见性,可以从CPU中直接拿到所要的数据,当对这个数据进行操作时,也会第一时间被保存到CPU当中。

package com.xxxx.thread;

public class Demo03 {
    public static void main(String[] args) {
        Street street=new Street();
        new Thread(new Person(street)).start();
        new Thread(new Car(street)).start();
    }
}
class Street{
    private volatile boolean flag=false;

    // false 走
    public  void we(){
        if(flag!=false){
            
        }else{
            System.out.println("人走.....");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag=true;
        }
    }

    // true 走
    public  void ns(){
        if(flag!=true){

        }else{
            System.out.println("车走.....");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag=false;
        }
    }
}
class Person implements Runnable{
    private Street street;

    public Person(Street street) {
        this.street = street;
    }

    @Override
    public void run() {
        while (true){
            street.we();
        }
    }
}
class Car implements Runnable{
    private Street street;

    public Car(Street street) {
        this.street = street;
    }

    @Override
    public void run() {
        while (true){
            street.ns();
        }
    }
}
}

ThreadLocal

是一个操作本地线程隔离的数据的工具类,它本身并不存储数据,真正存储数据的仍然是线程Thread对象本身,Thread对象内部有一个threadLocals用来作为本地数据。
每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

//
public class MybatisUtil {
    private static SqlSessionFactory factory = null;
    private static ThreadLocal<SqlSession> th = new ThreadLocal<>();
    static {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获得session对象
    public static SqlSession getSession() {
        SqlSession sqlSession = th.get();
        if (sqlSession == null) {
            sqlSession = factory.openSession(true);
            th.set(sqlSession);
        }
        return th.get();
    }
    //关闭session的操作
    public static void closed() {
        SqlSession sqlSession = th.get();
        if (sqlSession != null) {
            sqlSession.close();
        }
        th.set(null);
    }
}

关键词:多线程,并发编程,实现,同步,同步机,机制