2.Java多线程----同步代码、同步方法、Lock锁

前言 在多个线程中,如果有共享的数据,在操作共享数据的时候,可能会出现线程不安全的情况;
例如:

class thread extends Thread{ privatestatic int number = 1; @Override public void run() { for (int i = 0; i <10 ; i++) { number += 1; if(number < 10){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+number); } } } }public class ThreadTest { public static void main(String[] args) { thread thread = new thread(); thread thread1 = new thread(); thread.start(); thread1.start(); } }

结果
Thread-0:3 Thread-1:3 Thread-1:5 Thread-0:6 Thread-0:7 Thread-1:8 Thread-1:9 Thread-0:9

可以看出,结果并不是期望的2--9,其中有两个3和两个9,说明此时线程不安全
那么我们可以使用同步代码块等方法来处理这些不安全。
class thread extends Thread{ privatestatic int number = 1; @Override public void run() { for (int i = 0; i <10 ; i++) { synchronized (thread.class){ number += 1; if(number < 10){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+number); } } } } }

结果
Thread-1:2 Thread-1:3 Thread-0:4 Thread-1:5 Thread-1:6 Thread-0:7 Thread-1:8 Thread-1:9

结果正确,说明此时线程时安全的;
同步代码块:
//所谓的同步监视器,就是相当于一把锁,任何对象都可以充当一个同步监视器,但是要保证在需要同步的代码中,是同一个对象,即同一个锁,否则无法保证线程安全 //当使用继承thread类 实现时,由于每次开启一个线程时,都必须创建一个对象,此时无法使用this关键字,此时的this关键字 //代表的是不同的对象,此时可以使用当前类.class 如Test类 则使用Test.class来充当锁,因为class文件只加载一次 synchronized (同步监视器){ //同步代码 }

同步方法 同步方法和同步代码块类似,就是把代码块提取为一个方法
//同步方法:如果同步代码块是一个方法的话,可以直接写成同步方法 //此时如果使用runnable接口实现时,private synchronized void showMe() 此时锁 默认是this //当使用继承thread类 实现时,需要使用静态方法,此时锁 为类名.class

Lock锁
class Account{ private int acct = 10000; public void cost(int money){ acct -= money; System.out.println(acct); } }class Customer implements Runnable{ private Account account = new Account(); Lock lock = new ReentrantLock(); @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //lock.lock(); account.cost(10); //lock.unlock(); } } }public class LockTest { public static void main(String[] args) { Customer customer = new Customer(); Thread thread = new Thread(customer); Thread thread1 = new Thread(customer); thread.start(); thread1.start(); } }

结果
9980 9980 9970 9960 9950 9940 9930 9920 9910 9910 ...

可以发现此时,线程不安全
使用Lock锁
@Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } lock.lock(); account.cost(10); lock.unlock(); } }

结果
9990 9980 9970 9960 9950 9940 ....

【2.Java多线程----同步代码、同步方法、Lock锁】如果将lock.unlock()注释了的话,那么这个线程就会一直占用这个锁,其他进程就无法执行其中的代码。

    推荐阅读