多线程之synchronized同步语句块(5)

数据类型String的常量池特性

在JVM中具有String常量池缓存的功能。
将synchronized(string)同步块与String联合使用时,要注意常量池以带来的一些例外。

package test;

/**
 * @Author LiBinquan
 */
public class Service {
     public static void print(String str){
         try {
             synchronized (str) {
                 while (true) {
                     System.out.println(Thread.currentThread().getName());
                     Thread.sleep(1000);
                 }
             }
         }catch (InterruptedException e){
             e.printStackTrace();
         }
    }
}

线程1:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest1 extends Thread{

    private Service service;
    public ThreadTest1(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print("AA");
    }
}

线程2:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest2 extends Thread{
    private Service service;
    public ThreadTest2(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print("BB");
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();
        ThreadTest1 threadTest1 = new ThreadTest1(service);
        threadTest1.setName("A");
        threadTest1.start();
        ThreadTest2 threadTest2 = new ThreadTest2(service);
        threadTest2.setName("B");
        threadTest2.start();
    }
}

输出:
在这里插入图片描述
出现输出的情况就是因为String的两个值都是AA,两个线程持有相同的锁,所以造成线程B不能执行。这就是String常量池锁带来的问题。因此在大多数的情况下,同步synchronized代码块都不使用String作为锁对象,而改用其他,比如new Object()实例化一个Object对象,但它并不放入缓存中。
这边 我们修改一下 测试代码:

package test;

/**
 * @Author LiBinquan
 */
public class Service {
     public static void print(Object o){
         try {
             synchronized (o) {
                 while (true) {
                     System.out.println(Thread.currentThread().getName());
                     Thread.sleep(1000);
                 }
             }
         }catch (InterruptedException e){
             e.printStackTrace();
         }
    }
}

线程1:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest1 extends Thread{

    private Service service;
    public ThreadTest1(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print(new Object());
    }
}

线程2:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest2 extends Thread{
    private Service service;
    public ThreadTest2(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.print(new Object());
    }
}

输出:
在这里插入图片描述
交替打印的原因是持有的锁不是一个。

2.同步synchronized方法无限等待与解决

同步方法很容易死循环。

package test;

/**
 * @Author LiBinquan
 */
public class Service {
     synchronized public void methodA(){
         System.out.println("methodA begin");
         boolean isContinueRun = true;
         while (isContinueRun){

         }
         System.out.println("methodA end");
     }
     synchronized public void methodB(){
         System.out.println("methodB begin");
         System.out.println("methodB end");
     }
}

线程1:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest1 extends Thread{

    private Service service;
    public ThreadTest1(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.methodA();
    }
}

线程2:

package test;


/**
 * @Author LiBinquan
 */
public class ThreadTest2 extends Thread{
    private Service service;
    public ThreadTest2(Service service){
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.methodB();
    }
}

运行类:

package test;

/**
 * @Author LiBinquan
 */
public class Run {
    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();
        ThreadTest1 threadTest1 = new ThreadTest1(service);
        threadTest1.setName("A");
        threadTest1.start();
        ThreadTest2 threadTest2 = new ThreadTest2(service);
        threadTest2.setName("B");
        threadTest2.start();
    }
}

输出:
在这里插入图片描述
如上图所示,线程B永远得不到运行的机会,锁死了。
这时可以通过同步块来解决这样的问题。
更改后的代码如下:

package test;

/**
 * @Author LiBinquan
 */
public class Service {
    Object o1 = new Object();
      public void methodA(){
          synchronized (o1) {
              System.out.println("methodA begin");
              boolean isContinueRun = true;
              while (isContinueRun) {

              }
              System.out.println("methodA end");
          }
     }
     Object o2 = new Object();
      public void methodB(){
          synchronized(o2) {
              System.out.println("methodB begin");
              System.out.println("methodB end");
          }
     }
}

输出:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值