java thread synchronized 理解

在开始本文之前,建议阅读
范例解说Java里的线程概念与线程同步技术
一文,对Java的线程处理做一个全面了解。

线程同步指多个线程同时访问某资源时,采用一系列的机制以保证同时最多只能一个线程访问该资源。
为什么需要线程同步呢?
我们举一个最简单的例子来说明为什么需要线程同步。
比如有一本书(有且只有一本),交给多个售货员同时去卖;
如果其中任何一个售货员把这本书给卖了,其他售货员就不能再卖这本书了。
现实生活中,如果要保证该书不会被多个售货员同时卖掉,必须要有一种机制来保证:
比如,售货员应该拿到该书之后才能开始卖书,暂时拿不到的话就只能等该书被退回柜台。

售书的完整的例子可以参考 范例解说Java里的线程概念与线程同步技术 一文

这里,每一个售货员售书可以看作一个线程。欲售的书便是各线程需要共享的资源。
开始售书之前,需要取得该书(资源),取不到情况下等待:资源取得
开始售书之后,则需要取得对该书的独享控制(不让他人拿到该书):资源加锁
售完书时,需要通知柜台该书已售出;或者未售出时,把书退回柜台(通知他人可以拿到该书):资源解锁

synchronized控制线程同步的概念跟此完全一样。
Java里可以使用synchronized来同步代码块或者方法。
同步代码块例:

  1. synchronized(欲同步的对象obj) {   
  2.     需要同步的代码块   
  3. }  
synchronized(欲同步的对象obj) {
    需要同步的代码块
}


可以同步代码块。

synchronized (obj) 表示若多个线程同时访问时,只让其中一个线程最先取得obj对象并对其加锁,其它线程则阻塞直到取得obj对象的线程执行完代码块,此时被加锁的obj对象得到释放(解锁),其它线程得到通知取得该book对象继续执行。
很多情况下,可以使用synchronized (this){...}来同步代码块。但需要注意的是,使用this作为同步对象的话,如果同一个类中存在多个synchronized (this){...}代码块,其中任何一个synchronized(this)代码块处于被执行状态,则其它线程对其他synchronized(this)代码块的访问也会受到阻塞。
为了说明这个问题,我们举例说明:

HelloSynchronized.java

  1. public class HelloSynchronized {   
  2.   
  3.     public static void main(String[] args) {   
  4.         //   
  5.         HelloSynchronized helloSynchronized = new HelloSynchronized();   
  6.         //创建2个线程t1, t2,分别调用HelloSynchronized helloSynchronized的2个方法method1,与method2   
  7.         Thread t1 = new Thread(new HelloSynchronizedRunnalbe(helloSynchronized, "method1"), "t1");   
  8.         Thread t2 = new Thread(new HelloSynchronizedRunnalbe(helloSynchronized, "method2"), "t2");   
  9.            
  10.         t1.start();   
  11.         t2.start();   
  12.   
  13.     }   
  14.   
  15.     //synchronized public void method1() {    //同步方法   
  16.     public void method1() {   
  17.         synchronized (this) {    //同步块   
  18.   
  19.             System.out.println(Thread.currentThread().getName()   
  20.                     + " enter method1");   
  21.             try {   
  22.                 Thread.sleep(3000);   
  23.             } catch (InterruptedException e) {   
  24.                 // do nothing   
  25.             }   
  26.             System.out.println(Thread.currentThread().getName()   
  27.                     + " exit method1");   
  28.         }   
  29.     }   
  30.   
  31.     //synchronized public void method2() {    //同步方法   
  32.     public void method2() {   
  33.         synchronized (this) {    //同步块   
  34.             System.out.println(Thread.currentThread().getName()   
  35.                     + " enter method2");   
  36.             try {   
  37.                 Thread.sleep(3000);   
  38.             } catch (InterruptedException e) {   
  39.                 // do nothing   
  40.             }   
  41.             System.out.println(Thread.currentThread().getName()   
  42.                     + " exit method2");   
  43.         }   
  44.     }   
  45. }   
  46.   
  47. class HelloSynchronizedRunnalbe implements Runnable {   
  48.     private HelloSynchronized helloSynchronized;   
  49.     private String methodName;   
  50.     public HelloSynchronizedRunnalbe(HelloSynchronized helloSynchronized, String methodName) {   
  51.         this.helloSynchronized = helloSynchronized;   
  52.         this.methodName = methodName;   
  53.     }   
  54.     public void run() {   
  55.         if (methodName.equals("method1")) {   
  56.             helloSynchronized.method1();   
  57.         } else if (methodName.equals("method2")) {   
  58.             helloSynchronized.method2();   
  59.         }   
  60.     }   
  61. }  
public class HelloSynchronized {

    public static void main(String[] args) {
        //
        HelloSynchronized helloSynchronized = new HelloSynchronized();
        //创建2个线程t1, t2,分别调用HelloSynchronized helloSynchronized的2个方法method1,与method2
        Thread t1 = new Thread(new HelloSynchronizedRunnalbe(helloSynchronized, "method1"), "t1");
        Thread t2 = new Thread(new HelloSynchronizedRunnalbe(helloSynchronized, "method2"), "t2");
        
        t1.start();
        t2.start();

    }

    //synchronized public void method1() {    //同步方法
    public void method1() {
        synchronized (this) {    //同步块

            System.out.println(Thread.currentThread().getName()
                    + " enter method1");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // do nothing
            }
            System.out.println(Thread.currentThread().getName()
                    + " exit method1");
        }
    }

    //synchronized public void method2() {    //同步方法
    public void method2() {
        synchronized (this) {    //同步块
            System.out.println(Thread.currentThread().getName()
                    + " enter method2");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // do nothing
            }
            System.out.println(Thread.currentThread().getName()
                    + " exit method2");
        }
    }
}

class HelloSynchronizedRunnalbe implements Runnable {
    private HelloSynchronized helloSynchronized;
    private String methodName;
    public HelloSynchronizedRunnalbe(HelloSynchronized helloSynchronized, String methodName) {
        this.helloSynchronized = helloSynchronized;
        this.methodName = methodName;
    }
    public void run() {
        if (methodName.equals("method1")) {
            helloSynchronized.method1();
        } else if (methodName.equals("method2")) {
            helloSynchronized.method2();
        }
    }
}



运行结果为:

t1 enter method1
t1 exit method1
t2 enter method2
t2 exit method2

等到线程t1结束后,t2才开始运行(t2受到阻塞)

再把synchronized (this)去掉,运行结果为:

t1 enter method1
t2 enter method2
t1 exit method1
t2 exit method2

线程t1,t2同时运行

同步方法例:

  1. synchronized private void sellBook(Book book) {   
  2. ...   
  3. }  
synchronized private void sellBook(Book book) {
...
}


这种方法其实相当于

  1. private void sellBook(Book book) {   
  2.     synchronized(this) {   
  3.         ...   
  4.     }   
  5. }  
private void sellBook(Book book) {
    synchronized(this) {
        ...
    }
}


由于默认采用this作为同步对象,所以当一个类中有多个synchronized方法时,同样会存在以上问题:即如果有一个线程访问其中某个synchronized方法时,直到该方法执行完毕,其它线程对其它synchronized方法的访问也将受到阻塞。
大家可以把上面的例子稍加改造,去掉代码中的synchronized (this),改为synchronized public void method1(),synchronized public void method2()同步形式,运行后会得到同样结果。

多同步代码块synchronized(this){...}的多线程阻塞问题(包括synchronized同步方法),在并发处理的系统中(比如WEB服务器)会严重影响性能,建议慎重使用。可以使用synchronized(obj){...}缩小同步资源对象的范围来解决这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程Java语言中的一项非常重要的特性,它允许程序同时执行多个任务。多线程可以提高程序的并发性和性能,但是也带来了一些挑战,如线程安全、死锁、资源竞争等问题。 Java多线程的实现方式有两种:继承Thread类和实现Runnable接口。继承Thread类需要重写run()方法,该方法中包含线程需要执行的代码。实现Runnable接口需要实现run()方法,但是需要将Runnable对象传递给Thread类的构造方法中。 Java多线程的核心概念包括线程优先级、线程同步、线程通信、线程池等。线程优先级可以通过设置Thread类的setPriority()方法来进行设置,但是并不保证优先级高的线程一定会先执行。线程同步可以通过关键字synchronized来实现,它可以保证同一时刻只有一个线程可以访问共享资源。线程通信可以通过wait()、notify()、notifyAll()等方法来实现,它可以使线程之间进行协作。线程池可以通过Executor框架来实现,它可以实现线程的复用,减少线程创建和销毁的开销。 在使用Java多线程时,需要避免一些常见的问题,如死锁、资源竞争、线程安全等。死锁会导致线程之间相互等待,无法进行下去;资源竞争会导致多个线程同时访问共享资源,可能会导致数据的不一致;线程安全问题会导致多个线程同时访问共享资源,可能会导致数据的不一致或者程序崩溃等问题。 综上所述,Java多线程是一项非常重要的特性,它可以提高程序的并发性和性能,但是在使用时需要注意一些常见的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值