欢迎光临散文网 会员登陆 & 注册

java线程冲突与线程同步

2022-09-01 16:19 作者:虚云幻仙  | 我要投稿

/**
* 线程冲突和线程同步
* 当多个线程同时对同一个对象进行存取会出现线程冲突
* java中通过线程同步synchronized限制对象的并行访问,线程同步时当某个线程正在访问该对象,其他正要访问的线程进入阻塞状态,直至前一个线程执行完受同步影响的语句块,下一个线程再变为就绪状态
*/

public class Test8Thread implements Runnable{

   public static class Account{
       //创建账户类,存款不能为负数
       String id;
       int money;

       public Account(String id, int money) {
           this.id = id;
           this.money = money;
       }
   }

   Account targetAccount;
   //要访问的账户

   public Test8Thread(Account targetAccount) {
       this.targetAccount = targetAccount;
   }

   @Override
   public void run() {
       if (targetAccount.money>=800){
           System.out.println("正在取款,请稍等");
           try {
               Thread.sleep(500);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
           targetAccount.money -= 800;
           System.out.println("取款成功,剩余金额: "+targetAccount.money);
       }else {
           System.out.println("余额不足,取款失败");
       }
   }

   public static void main(String[] args) {
       Account a1 = new Account("101",1000);
       new Thread(new Test8Thread(a1),"1号取款人").start();
       new Thread(new Test8Thread(a1),"2号取款人").start();
       /*结果为:
       正在取款,请稍等
       正在取款,请稍等
       取款成功,剩余金额: 200
       取款成功,剩余金额: 200

       两个线程几乎同时读取到money=1000都判断>800,又几乎同时用1000-800赋值给money
       如果其中一个线程先一步完成money-=800,另一个线程会计算200-800赋值给money产生负数
        */

   }
}

class TakeMoney implements Runnable{
   Test8Thread.Account target;

   public TakeMoney(Test8Thread.Account target) {
       this.target = target;
   }


   @Override
   public void run() {
       synchronized (target){
           //synchronized(锁对象){同步代码} 在执行语句块的内容时给对象(必须是对象)上锁,同步代码执行时具有线程互斥的能力(并行变串行)
           if (target.money>=800){
               System.out.println(Thread.currentThread().getName()+"正在取款,请稍等");
               try {
                   Thread.sleep(500);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
               target.money-=800;
               System.out.println(Thread.currentThread().getName()+"取款成功");
           }else {
               System.out.println(Thread.currentThread().getName()+"余额不足,取款失败");
           }
       }
       System.out.println(Thread.currentThread().getName()+"结束,余额为:"+target.money);
       //同步语句块外的内容仍然为并行
   }

   public static void reset(Test8Thread.Account t){
       synchronized (t){
           try {
               Thread.sleep(3000);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
           t.money=700;
       }
   }
   public static void main(String[] args) {
       Test8Thread.Account a1 = new Test8Thread.Account("101",1000);
       Thread t1 = new Thread(new TakeMoney(a1),"1号取款人");
       Thread t2 = new Thread(new TakeMoney(a1),"2号取款人");
       t1.start();
       t2.start();
       /*结果为:
       1号取款人正在取款,请稍等
       1号取款人取款成功
       1号取款人结束,余额为:200
       2号取款人余额不足,取款失败
       2号取款人结束,余额为:200

       t1执行synchronized语句时t2阻塞,等t1执行完语句后t2进入就绪状态,判定money<800取款失败
        */


       Test8Thread.Account tar = new Test8Thread.Account("102",1000);
       Thread t3 = new Thread(new TakeMoney(tar));
       t3.start();
       reset(tar);
       /*结果为
       Thread-0余额不足,取款失败
       Thread-0结束,余额为:700

       synchronized锁对象为同一对象时,执行不同语句块也会线程互斥
        */

   }
}

class CustomizeArray{
   private int[] arr = new int[10];
   public synchronized void initialize(){
       //synchronized修饰方法时锁对象为this/当前对象
       for (int i =0;i<10;i++){
           arr[i]=i;
       }
       try {
           Thread.sleep(500);
       } catch (InterruptedException e) {
           throw new RuntimeException(e);
       }
       System.out.println(Arrays.toString(arr));
   }

   public synchronized void sum(){
       synchronized (this){
           //锁对象为this,并且语句块涵盖整个方法体可改写为方法的修饰词
           int sum=0;
           for (int i:arr){
               sum+=i;
           }
           try {
               Thread.sleep(500);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
           System.out.println("和为:"+sum);
       }
   }
}
class InitialThread implements Runnable{
   //执行arr初始化
   CustomizeArray arr;

   public InitialThread(CustomizeArray arr) {
       this.arr = arr;
   }

   @Override
   public void run() {
       arr.initialize();
   }
}
class SumThread implements Runnable{
   //执行arr求和
   CustomizeArray arr;

   public SumThread(CustomizeArray arr) {
       this.arr = arr;
   }

   @Override
   public void run() {
       arr.sum();
   }
}
class Test9Thread{
   public static void main(String[] args) {
       CustomizeArray arr = new CustomizeArray();
       Thread t1 = new Thread(new InitialThread(arr));
       Thread t2 = new Thread(new SumThread(arr));
       t1.start();
       t2.start();
       //结果为
       // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
       //和为:45
       //多个线程访问同一个锁对象,任何一个线程执行任何一段同步代码时,都会线程互斥,其他线程进入阻塞状态等待唤醒

   }
}

java线程冲突与线程同步的评论 (共 条)

分享到微博请遵守国家法律