Java多线程同步解决线程安全的理解

Java多线程使用同步机制处理线程安全的理解

** ** Java中多线程的创建这里只说两种。
1.继承于Thread类
①即创建一个Thread的子类
②重写Thread类中的run()方法,方法体中写线程执行的操作
③通过子类的对象调用Thread类中的start()方法,通过start()方法启动线程,
由于通过动态绑定的机制,最终调用该线程的run()方法,即子类重写的。

//创建一个继承Thread类的子类 class ThreadTest extends Thread{      //重写父类中的run()方法     @Override     public void run() {         for (int i = 0; i < 20; i++) {             System.out.println(currentThread().getName() + ":" + i);         }     } }  public class Textkang {     public static void main(String[] args) {         //创建子类对象         ThreadTest threadTest = new ThreadTest();         ThreadTest threadTest1 = new ThreadTest();         //设置线程名         threadTest.setName("线程1:");         threadTest1.setName("线程2:");         //调用start()方法启动线程         threadTest.start();         threadTest1.start();     } }  
Java多线程同步解决线程安全的理解

2.实现Runnable接口
①创建一个Runnable接口的实现类
②实现Runnable接口中的虚拟方法run(),方法体中写线程执行的操作
③以该实现类对象为参数传入Thread类的构造器中,创建Thread类的对象,
并通过Thread类的对象调用start()方法去启动该线程,调用该线程的run()方法

//创建一个是实现Runnable接口的实现类 class ThreadTest implements Runnable{      //实现接口中的run()方法     @Override     public void run() {         for (int i = 0; i < 20; i++) {             System.out.println(Thread.currentThread().getName() + ":" + i);         }     } }  public class Textkang {     public static void main(String[] args) {         //创建实现类对象         ThreadTest threadTest = new ThreadTest();         //创建新线程         Thread thread1 = new Thread(threadTest);         Thread thread2 = new Thread(threadTest);         //设置线程名字         thread1.setName("线程一:");         thread2.setName("线程二:");         //调用start()方法启动线程         thread1.start();         thread2.start();     } } 
Java多线程同步解决线程安全的理解

多线程操作共享数据时,有时会出现线程安全的问题。

//创建一个销售商品的类,继承于Thread类 class Sale extends Thread{     //设置商品数量为50个     private static int  commodity = 50;     @Override     public void run() {         for(;;){             if(commodity > 0){                 System.out.println(getName() + ":商品为:" + commodity + "号");                 commodity--;             }else {                 break;             }         }     } }  public class SaleTest {     public static void main(String[] args) {         //设置三个售货口一起销售一批商品         Sale sale1 = new Sale();         Sale sale2 = new Sale();         Sale sale3 = new Sale();         //设置售货口名字         sale1.setName("售货口1:");         sale2.setName("售货口2:");         sale3.setName("售货口3:");          sale1.start();         sale2.start();         sale3.start();      } } 

这里没用做啥处理,所以出现了线程安全问题,比如同一个货物被三个窗口售卖,这显然是不被允许的。
Java多线程同步解决线程安全的理解
同样用实现Runnable接口的方式如果不做处理,一样可能出现线程安全问题。
这里就不上代码了。

Java中通过同步机制处理线程安全问题,关键字://创建一个销售商品的类,继承于Thread类 class Sale extends Thread { //设置商品数量为50个 private static int commodity = 500; @Override public void run() { for(;;) { sales(); } } public static synchronized void sales() {//这里的同步监视器是该类本身 Sale.class if (commodity > 0) { try { sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "商品为:" + commodity + "号"); commodity--; } } } public class SaleTest { public static void main(String[] args) { //设置三个售货口一起销售一批商品 Sale sale1 = new Sale(); Sale sale2 = new Sale(); Sale sale3 = new Sale(); //设置售货口名字 sale1.setName("售货口1:"); sale2.setName("售货口2:"); sale3.setName("售货口3:"); sale1.start(); sale2.start(); sale3.start(); } }

结果由于是竖着的,不好截图,就没弄。可以复制代码上机验证。

②当使用实现Runnable接口的方式传进线程,开多个线程,也只new了一个实现类对象,操作共享数据时,用同步方法 处理线程安全问题的话,同步方法不用声明为静态的,抢锁同上。

//创建一个销售商品的类,实现Runnable接口 class Sale implements Runnable {     //设置商品数量为50个     private static int commodity = 500;      @Override     public void run() {         for(;;) {             sales();         }     }     public static synchronized void sales() {//这里的同步监视器是该类本身 Sale.class             if (commodity > 0) {                  try {                     Thread.sleep(10);                 } catch (InterruptedException e) {                     e.printStackTrace();                 }                  System.out.println(Thread.currentThread().getName() + "商品为:" + commodity + "号");                 commodity--;             }         }     }  public class SaleTest {     public static void main(String[] args) {         //设置三个售货口一起销售一批商品         Sale sale = new Sale();         Thread sale1 = new Thread(sale);         Thread sale2 = new Thread(sale);         Thread sale3 = new Thread(sale);         //设置售货口名字         sale1.setName("售货口1:");         sale2.setName("售货口2:");         sale3.setName("售货口3:");          sale1.start();         sale2.start();         sale3.start();      } } 

二、使用同步代码块理解
使用同步代码块:①当使用当使用继承于Thread类的方式创建线程,开多个线程时,就要new多个子类的对象,操作共享数据时,用同步代码块的话,因为多个对象,每个对象都有自己的run()方法,同步代码块在run()方法中,也有多个,但是锁是唯一的,即不管有多少个run()方法,只有一个锁,当某个线程抢到锁,它就顺利执行,其他线程则等待锁被释放。

//创建一个销售商品的类,继承于Thread类 class Sale extends Thread{     //设置商品数量为50个     private static int  commodity = 50;     @Override     public void run() {         for(;;){             synchronized(Sale.class) {//这里是用的该类的类名作为的同步监视器,                                     // 也可用其他类的对象作为同步监视器,切记同步监视器要唯一                 if (commodity > 0) {                     System.out.print(getName() + "商品为:" + commodity + "号");                     commodity--;                 } else {                     break;                 }             }         }     } }  public class SaleTest {     public static void main(String[] args) {         //设置三个售货口一起销售一批商品         Sale sale1 = new Sale();         Sale sale2 = new Sale();         Sale sale3 = new Sale();         //设置售货口名字         sale1.setName("售货口1:");         sale2.setName("售货口2:");         sale3.setName("售货口3:");          sale1.start();         sale2.start();         sale3.start();      } } 

②当使用实现Runnable接口的方式传进线程,开多个线程,也只new了一个实现类对象,操作共享数据时,用同步代码块的话,由于只创建了一个实现类对象,那么run()方法就只有一份,同步代码块也只有一份,依然是哪个线程抢到锁,就执行,其他线程等待。

//创建一个销售商品的类,实现Runnable接口 class Sale implements Runnable {     //设置商品数量为50个     private static int commodity = 500;      @Override     public void run() {         for(;;) {             synchronized (this){//这里使用的是该对象作为的同步监视器,                             // 还可以用其他的对象做同步监视器,保证唯一性就行                 if(commodity > 0) {                      try {                         Thread.sleep(15);                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                      System.out.println(Thread.currentThread().getName() + "商品为:" + commodity + "号");                     commodity--;                 }else {                     break;                 }             }         }          }     }  public class SaleTest {     public static void main(String[] args) {         //设置三个售货口一起销售一批商品         Sale sale = new Sale();         Thread sale1 = new Thread(sale);         Thread sale2 = new Thread(sale);         Thread sale3 = new Thread(sale);         //设置售货口名字         sale1.setName("售货口1:");         sale2.setName("售货口2:");         sale3.setName("售货口3:");          sale1.start();         sale2.start();         sale3.start();      } }