线程同步机制

Posted 技术很low的瓜贼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程同步机制相关的知识,希望对你有一定的参考价值。

文章目录

线程同步机制

概念:

  • 当多个线程同时访问一种共享资源时,可能会造成数据的覆盖等不一致问题,此时需要对线程之间进行通信和协调,该机制叫做线程同步机制
  • 多个线程并发读写同一个临界资源时会发生线程并发安全问题
    异步操作:多线程并发的操作,各自独立运行
    同步操作:多线程串行的操作,先后执行的顺序

实现方式:

  • 在Java语言中使用synchronized关键字来实现同步/对象锁机制从而保证线程执行的原子性

使用同步代码块方式:

使用同步代码块的方式实现部分代码的锁定,格式如下:
synchronized(类类型的引用)
编写所有需要锁定的代码;

案例代码:

package 线程;

/**
 * 线程的同步机制
 * 同步代码块的方式一
 */
public class AccountTest implements Runnable

    private int balance; // 用于描述账户余额

    public AccountTest() 
    

    public AccountTest(int balance) 
        this.balance = balance;
    

    @Override
    public String toString() 
        return "AccountTest" +
                "balance=" + balance +
                '';
    

    public int getBalance() 
        return balance;
    

    public void setBalance(int balance) 
        this.balance = balance;
    

    @Override
    public void run() 
        synchronized (this) 
            System.out.println(Thread.currentThread().getName() + "正在操作");
            int temp = getBalance();
            // 模拟取款
            System.out.println("正在取款请稍后");
            if (temp > 200) 
                System.out.println("正在出钞,请稍后");
                temp -= 200;
                try 
                    Thread.sleep(5000);
                    System.out.println("取钞完成");
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
             else 
                System.out.println("余额不足");
            

            // 模拟将最新的账户余额写入后台
            setBalance(temp);
            System.out.println(getBalance());
        

    

    public static void main(String[] args) 
        AccountTest at = new AccountTest(1000);
        Thread t1 = new Thread(at);
        Thread t2 = new Thread(at);
        t1.start();
        t2.start();
        try 
            t1.join();
            t2.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
    



使用同步方法的方式

直接使用synchronized关键字来修饰整个方法即可
该方式等价于:
synchronized(this) 整个方法体的代码

案例代码:

  • Runnable代码:
/**
 * 线程的同步机制
 * 直接使用synchronized来修饰整个方法
 */
public class AccountTest3 implements Runnable

    private int balance; // 用于描述账户余额

    public AccountTest3() 
    

    public AccountTest3(int balance) 
        this.balance = balance;
    

    @Override
    public String toString() 
        return "AccountTest" +
                "balance=" + balance +
                '';
    

    public int getBalance() 
        return balance;
    

    public void setBalance(int balance) 
        this.balance = balance;
    

    @Override
    public synchronized void run() 
            System.out.println(Thread.currentThread().getName() + "正在操作");
            int temp = getBalance();
            // 模拟取款
            System.out.println("正在取款请稍后");
            if (temp > 200) 
                System.out.println("正在出钞,请稍后");
                temp -= 200;
                try 
                    Thread.sleep(5000);
                    System.out.println("取钞完成");
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
             else 
                System.out.println("余额不足");
            

            // 模拟将最新的账户余额写入后台
            setBalance(temp);
            System.out.println(getBalance());
    

    public static void main(String[] args) 
        AccountTest at = new AccountTest(1000);
        Thread t1 = new Thread(at);
        Thread t2 = new Thread(at);
        t1.start();
        t2.start();
        try 
            t1.join();
            t2.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
    



  • Thread代码:

/**
 * 线程的同步机制
 * synchronized直接修饰
 */
public class AccountTest4 extends Thread

    private int balance; // 用于描述账户余额

    public AccountTest4()

    
    public AccountTest4(int balance) 
        this.balance = balance;
    

    public int getBalance() 
        return balance;
    

    public void setBalance(int balance) 
        this.balance = balance;
    

    @Override
    public synchronized void run() 

            int temp = getBalance();

            System.out.println("正在取款,请稍后");
            if (temp >= 200) 
                System.out.println("正在出钞");
                temp -= 200;
                try 
                    Thread.sleep(5000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
            
            setBalance(temp);
            System.out.println("余额" + getBalance());
    

    public static void main(String[] args) 
        AccountTest2 at2 = new AccountTest2(1000);
        at2.start();
        AccountTest2 at22 = new AccountTest2(1000);
        at22.start();

        try 
            at2.join();
            at22.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
    



静态方法锁定的方式

  • 当我们对一个静态方法加锁,如: public synchronized static void xxx()….
  • 那么该方法锁的对象是类对象。每个类都有唯一的一个类对象。获取类对象的方式:类名.class
  • 静态方法与非静态方法同时使用了synchronized后它们之间是非互斥关系的
  • 原因在于:静态方法锁的是类对象而非静态方法锁的是当前方法所属对象
  • 使用synchronized保证线程同步应当注意
    • 多个需要同步的线程在访问同步块时,看到的应该是同一个锁对象引用。
    • 在使用同步块时应当尽量减少同步范围以提高并发的执行效率

案例代码:

/**
 * 线程的同步机制
 * 同步代码块方式二
 */
public class AccountTest2 extends Thread

    private int balance; // 用于描述账户余额
    private static Demo dm = new Demo();

    public AccountTest2()

    
    public AccountTest2(int balance) 
        this.balance = balance;
    

    public int getBalance() 
        return balance;
    

    public void setBalance(int balance) 
        this.balance = balance;
    

    @Override
    public void run() 

        synchronized (dm) 
            int temp = getBalance();

            System.out.println("正在取款,请稍后");
            if (temp >= 200) 
                System.out.println("正在出钞");
                temp -= 200;
                try 
                    Thread.sleep(5000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
            
            setBalance(temp);
            System.out.println("余额" + getBalance());
        

    

    public static void main(String[] args) 
        AccountTest2 at2 = new AccountTest2(1000);
        at2.start();
        AccountTest2 at22 = new AccountTest2(1000);
        at22.start();

        try 
            at2.join();
            at22.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
    

class Demo

使用Lock(锁)实现线程同步

  • 从Java5开始提供了更强大的线程同步机制—使用显式定义的同步锁对象来实现
  • java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具
  • 该接口的主要实现类是ReentrantLock类,该类拥有与synchronized相同的并发性,在以后的线程安全控制中,经常使用ReentrantLock类显式加锁和释放锁
  • 常用方法:
方法功能
ReentrantLock()使用无参方式构造对象
void lock()获取锁
void unlock()释放锁

案例代码:

  • Runnable代码:
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程的同步机制
 * 使用Lock实现线程的同步
 */
public class AccountTest5 implements Runnable 

    private int balance; // 用于描述账户余额

    private ReentrantLock lock = new ReentrantLock(); // 准备了一把锁
    public AccountTest5() 
    

    public AccountTest5(int balance) 
        this.balance = balance;
    

    @Override
    public String toString() 
        return "AccountTest" +
                "balance=" + balance +
                '';
    

    public int getBalance() 
        return balance;
    

    public void setBalance(int balance) 
        this.balance = balance;
    

    @Override
    public void run() 
        lock.lock(); // 关锁
        System.out.println(Thread.currentThread().getName() + "正在操作");
        int temp = getBalance();
        // 模拟取款
        System.out.println("正在取款请稍后");
        if (temp > 200) 
            System.out.println("正在出钞,请稍后");
            temp -= 200;
            try 
                Thread.sleep(5000);
                System.out.println("取钞完成");
             catch (InterruptedException e) 
                e.printStackTrace();
            
         else 
            System.out.println("余额不足");
        

        // 模拟将最新的账户余额写入后台
        setBalance(temp);
        System.out.println(getBalance());
        lock.unlock(); // 开锁
    

    public static void main(String[] args) 
        AccountTest at = new AccountTest(1000);
        Thread t1 = new Thread(at);
        Thread t2 = new Thread(at);
        t1.start();
        t2.start();
        try 
            t1.join();
            t2.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
    


  • Thread代码:
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程的同步机制
 * 使用Lock锁实现同步机制
 */
public class AccountTest6 extends Thread

    private int balance; // 用于描述账户余额

    private ReentrantLock lock = new ReentrantLock(); // 准备一把锁
    public AccountTest6()

    
    public AccountTest6(int balance) 
        this.balance = balance;
    

    public int getBalance() 
        return balance;
    

    public void setBalance(int balance) 
        this.balance = balance;
    

    @Override
    public void run() 

        lock.lock();
        int temp = getBalance();

        System.out.println("正在取款,请稍后");
        if (temp >= 200) 
            System.out.println("正在出钞");
            temp -= 200;
            try 
                Thread.sleep(5000);
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
        setBalance(temp);
        System.out.println("余额" + getBalance());

        lock.unlock();
    

    public static void main(String[] args) 
        AccountTest2 at2 = new AccountTest2(1000JavaSE:线程同步机制

java线程之线程同步

线程同步机制

多线程同步的五种方法

java多线程有几种实现方法?线程之间如何同步

java并发之线程同步(synchronized和锁机制)