6.11Java多线程、并发、同步、synchronized方法

2021/6/12 14:26:10

本文主要是介绍6.11Java多线程、并发、同步、synchronized方法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

6.11Java多线程、并发、同步、synchronized方法

摸索前进

package iostudy.synchro;
​
/**
 * 多线程并发、同步保证数据准确性,效率尽可能高和好
 * 线程安全:
 * 1、在并发池保证数据的准确性
 * 2、同时保证效率尽可能高
 * synchronized
 * 1、同步方法
 * 2、同步块
 * @since JDK 1.8
 * @date 2021/6/11
 * @author Lucfier
 */
public class SynTestNo1 {
    public static void main(String[] args) {
​
        /*创建资源类对象*/
        SafeWeb12306 safeWeb12306 = new SafeWeb12306();
​
        /*多个线程*/
        new Thread(safeWeb12306,  "fe斯特").start();
        new Thread(safeWeb12306, "赛肯").start();
        new Thread(safeWeb12306, "瑟得").start();
    }
}
​
/**
 * 创建一个资源类,测试同步方法
 */
class SafeWeb12306 implements Runnable{
    /*票数*/
    private int ticketNums = 99;
    /*设置开关*/
    private boolean flag = true;
    /*重写run方法--->多线程执行入口*/
    @Override
    public void run(){
        while (flag){
            /*在下面写线程的具体执行方法*/
            test();
        }
    }
​
    /**
     * 封装一个线程内部具体方法类
     */
    public synchronized void test(){
​
        /*判断资源数、改变开关、结束方法*/
        //每次方法一开始就执行判断
        if (ticketNums<0){
            /*改变开关状态*/
            flag = false;
            /*结束方法*/
            return;
        }
​
        /*模拟延时*/
        try {
            /*线程携带数据锁休眠*/
            Thread.sleep(200);
        }catch (InterruptedException e){
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        /*打印当前线程对象信息--->获取当前线程方法*/
        System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
​
    }
}

之前出现负数资源的原因

  • 最后一位资源为1

  • 三个线程同时访问该资源(A,B,C)

  • B线程先运行,但是B不<=0,所以进行延时等待。B没有修改数据

  • 此时A和C也进入线程体。此时B刚好修改数据而A和C访问到的资源数还是1

出现线程访问到相同资源数的原因

  • 每个线程都有一个工作空间与主存交互

  • 线程会round(加载)、store(存储)

  • 当B线程没有将工作空间的修改数据返回主存的时候A、C线程也对主存的数据拷贝了一份

  • 所以还是原来的资源数而不是更新后的资源数

这样就实现了同步,(线程大概率按顺序访问)

synchronized方法实例
package iostudy.synchro;
​
/**
 * 多线程并发、同步保证数据准确性,效率尽可能高和好
 * 线程安全:
 * 1、在并发池保证数据的准确性
 * 2、同时保证效率尽可能高
 * synchronized
 * 1、同步方法
 * 2、同步块
 * @since JDK 1.8
 * @date 2021/6/11
 * @author Lucfier
 */
public class SynTestNo1 {
    public static void main(String[] args) {
​
        /*创建资源类对象*/
        SafeWeb12306 safeWeb12306 = new SafeWeb12306();
​
        /*多个线程*/
        new Thread(safeWeb12306,  "fe斯特").start();
        new Thread(safeWeb12306, "赛肯").start();
        new Thread(safeWeb12306, "瑟得").start();
    }
}
​
/**
 * 创建一个资源类,测试同步方法
 */
class SafeWeb12306 implements Runnable{
    /*票数*/
    private int ticketNums = 1000;
    /*设置开关*/
    private boolean flag = true;
    /*重写run方法--->多线程执行入口*/
    @Override
    public void run(){
        while (flag){
​
            /*模拟延时*/
            try {
                /*线程携带数据锁休眠*/
                Thread.sleep(200);
            }catch (InterruptedException e){
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
​
            /*在下面写线程的具体执行方法*/
            test();
​
        }
    }
​
    /**
     * 封装一个线程内部具体方法类
     */
    public synchronized void test(){
​
        /*判断资源数、改变开关、结束方法*/
        //每次方法一开始就执行判断
        if (ticketNums<0){
            /*改变开关状态*/
            flag = false;
            /*结束方法*/
            return;
        }
​
        /*打印当前线程对象信息--->获取当前线程方法*/
        System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
​
    }
    /*
    1、该资源的锁操作了两个属性
        1、ticketNums
        2、flag
    该方法是成员方法,操作的都是对象(this)SafeWeb12306--->锁的是对象
    方法当中的资源必须是必须是对象的资源才能使用,非该对象的资源无法锁住
    使用方法的时候判断对象是否能使用,有了锁就无法使用对象--->锁了对象的资源(方法当中都是与对象相关的资源。如果不是就可能是锁失败了)
     */
}
synchronized锁定目标不对(锁定对象不对),导致锁定失败

AccountTest类:

package iostudy.synchro;
​
/**
 * 创建一个账户类--->资源类
 * @since JDK 1.8
 * @date 2021/6/10
 * @author Lucifer
 */
public class AccountTest {
​
        /*定义资源属性*/
        int money; //金额
        String name; //名称字符串
​
        /*创建构造器*/
        public AccountTest(int money, String name) {
            this.money = money;
            this.name = name;
        }
​
}

锁定错误的线程同步类:

package iostudy.synchro;
​
public class SynTestNo2 {
​
    /*定义资源属性*/
    int money; //金额
    String name; //名称字符串
​
    public static void main(String[] args) {
​
        AccountTest accountTest = new AccountTest(100, "money");
        SafeDrawing you = new SafeDrawing(accountTest, 80, "Lucifer");
        SafeDrawing she = new SafeDrawing(accountTest, 90, "JunkingBoy");
        you.start();
        she.start();
​
    }
​
    /*创建构造器*/
    public SynTestNo2(int money, String name) {
        this.money = money;
        this.name = name;
    }
​
}
​
/**
 * 模拟提款机提款类--->多线程
 * @since JDK 1.8
 * @date 2021/6/10
 * @author Lucifer
 */
class SafeDrawing extends Thread{
​
    /*创建实现类对象--->面向对象的思想*/
    AccountTest accountTest; //取出的账户
    int drawingMoney; //取出的钱数
    int pocketTotal; //取出的钱的总数
​
    /*创建构造器,将属性定义为参数*/
    public SafeDrawing(AccountTest accountTest, int drawingMoney, String name) {
        super(name); //线程的名称
        this.accountTest = accountTest;
        this.drawingMoney = drawingMoney;
    }
​
    /*重写run方法--->线程的具体实现*/
    @Override
    public void run() {
        test();
    }
​
    //目标锁定不对,锁定失败
    /*
    这里不是锁定this,而应该锁定account
     */
    public synchronized void test(){
        /*在存钱和取钱的时候加入条件*/
        if (accountTest.money-drawingMoney<0){
            /*结束方法*/
            return;
        }
​
        /*模拟取款的网络延迟*/
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        /*
        理论上说加了判断就会控制结果
        但是实际上不会,这个需要对资源+锁实现控制的效果
         */
​
        /*账户的金额-取出的金额*/
        accountTest.money -= drawingMoney;
        /*口袋中的金额+取出的钱*/
        pocketTotal += drawingMoney;
​
        /*因为继承了父类所以可以直接用this--->获取线程的名称*/
        System.out.println(this.getName() + "--->账户余额为:" + accountTest.money);
        System.out.println(this.getName() + "--->身上余额为:" + pocketTotal);
​
    }
    /*
    该方法的this是取款机的this,应该锁住的资源是AccountTest类的对象
     */
}


这篇关于6.11Java多线程、并发、同步、synchronized方法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程