java线程同步与互斥

来源:互联网 发布:java 分布式事务 编辑:程序博客网 时间:2024/06/06 21:38

同步:用关键字synchronized给针对共享资源的操作(方法或代码块)加锁,这把锁就叫作互斥锁。所以有两种加锁方式,一种是同步方法,一种是同步代码块。如图:


特别提示:锁住的不是方法,也不是代码块,而是对象,并且是同一个对象。也就是说一个线程正在调用该对象的同步方法,如果还没有执行完成,那么另一个线程就无法调用该对象的所有同步方法或代码块(会阻塞),当然没有加synchronized关键字的方法或代码块不会被锁住。

示例代码1:

class ShareObj{String[] colors1={"red","orange","yellow", "green","blue","indigo","purple","black","white"};String[] colors2={"红色","橙色","黄色", "绿色","蓝色","靛色","紫色","黑色","白色"};synchronized void printColor(String thName){if(thName.equals("color")){for(int i=0;i<colors1.length;i++){try {System.out.println(colors1[i]);Thread.sleep((long)(Math.random()*2000));} catch (InterruptedException e) {e.printStackTrace();}}}else if(thName.equals("颜色")){for(int i=0;i<colors2.length;i++){try {System.out.println(colors2[i]);Thread.sleep((long)(Math.random()*2000));} catch (InterruptedException e) {e.printStackTrace();}}}}}class CreateByThread extends Thread{ShareObj obj=null;public CreateByThread(String name,ShareObj obj){super(name);this.obj=obj;}public void run() {obj.printColor(this.getName());}}public class ThreadSynExc {public static void main(String[] args) {ShareObj obj=new ShareObj();CreateByThread cbt1=new CreateByThread("color",obj);CreateByThread cbt2=new CreateByThread("颜色",obj);cbt1.start();cbt2.start();}}
如果printColor方法没有加synchronized关键字,运行结果如下:

红色

redorangeyellow橙色green黄色绿色blue蓝色indigopurple靛色紫色blackwhite黑色白色

这就是两个线程都在调用printColor方法的结果,相互竞争资源,没有规律。

如果我们要求一个线程在调用printColor的时候,其它线程不能调用,我们就可以在printColor前面加上synchronized关键字
运行结果如下所示:

红色橙色黄色绿色蓝色靛色紫色黑色白色redorangeyellowgreenblueindigopurpleblackwhite

示例代码2:

public class Bank {private int balance =0;//账户余额      //存钱      public void addMoney(int money){      System.out.println("======存钱start=======");    balance +=money;          System.out.println(System.currentTimeMillis()+"存进:"+money);          System.out.println("账户余额:"+balance);          System.out.println("======存钱end=======");    }      //取钱      public void subMoney(int money){     System.out.println("======取钱start=======");        if(balance-money < 0){              System.out.println("余额不足");             System.out.println("======取钱end=======");            return;          }          balance -=money;          System.out.println(+System.currentTimeMillis()+"取出:"+money);          System.out.println("账户余额:"+balance);         System.out.println("======取钱end=======");    }  }public class SyncBankTest {public static void main(String[] args) {final Bank bank=new Bank();          Thread tadd=new Thread(new Runnable() {              public void run() {                  while(true){                      try {                      Thread.sleep(1000);                    } catch (InterruptedException e) {                          e.printStackTrace();                      }                      bank.addMoney(100);                                        }              }          });          Thread tsub = new Thread(new Runnable() {              public void run() {                  while(true){                      bank.subMoney(100);                      try {                      Thread.sleep(1000);                    } catch (InterruptedException e) {                          e.printStackTrace();                      }                     }              }          });          tsub.start();          tadd.start();  }}

如果不加synchronized关键字,运行结果是这样的:

======存钱start=======1505238241890存进:100账户余额:100======存钱end=============取钱start=======1505238242890取出:100账户余额:0======存钱start=============取钱end=======1505238242890存进:100账户余额:100======存钱end=============取钱start=======1505238243890取出:100账户余额:0======取钱end=============存钱start=======1505238243890存进:100账户余额:100======存钱end=======

是不是看起来很混乱,看不明白存钱取钱是怎么回事?

如果在存钱和取钱的方法上加上synchronized关键字,运行结果如下所示:

======取钱start=======余额不足======取钱end=============存钱start=======1505238048821存进:100账户余额:100======存钱end=============取钱start=======1505238048834取出:100账户余额:0======取钱end=============存钱start=======1505238049821存进:100账户余额:100======存钱end=============取钱start=======1505238049834取出:100账户余额:0======取钱end=============存钱start=======1505238050821存进:100账户余额:100======存钱end=============取钱start=======1505238050834取出:100账户余额:0======取钱end=======

怎么样,是不是感觉可以理解了!!

示例代码3:

class SyncCla {        public synchronized void test() {          System.out.println("test开始..");          try {              Thread.sleep(1000);          } catch (InterruptedException e) {              e.printStackTrace();          }          System.out.println("test结束..");      }  }    class MyThread extends Thread {        public void run() {          SyncCla sync = new SyncCla();          sync.test();      }  }    public class Main {        public static void main(String[] args) {          for (int i = 0; i < 3; i++) {              Thread thread = new MyThread();              thread.start();          }      }  } 

运行结果:

test开始..test开始..test开始..test结束..test结束..test结束..

可以看出来,上面的程序起了三个线程,同时运行SyncCla类中的test()方法,虽然test()方法加上了synchronized,但是还是同时运行起来,貌似synchronized没起作用。因为SyncCla被new了三次,每个线程分别是一个不同对象,所以synchronized不起作用了

说明synchronized关键字是对同一对象加锁!!!!切记切记!



原创粉丝点击