Java多线程之synchronized(五)


上篇介绍了用synchronized修饰static方式来实现“Class 锁”,今天要介绍另一种实现方式,synchronized(class)代码块,写法不一样但是作用是一样的。下面我附上一段代码来看一下synchronized(class)代码块的基本用法,如下:

public static void main(String[] args) {

		Service4 s1 = new Service4();
		Service4 s2 = new Service4();
		ThreadA a = new ThreadA(s1);
		ThreadB b = new ThreadB(s2);
		a.setName("A");
		b.setName("B");
		a.start();
		b.start();
	}

	public static class ThreadA extends Thread {

		private Service4 service;

		public ThreadA(Service4 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {

			super.run();
			service.printA();
		}
	}

	public static class ThreadB extends Thread {

		private Service4 service;

		public ThreadB(Service4 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {

			super.run();
			service.printB();
		}
	}

}

class Service4 {

	static public void printA() {
		synchronized (Service4.class) {
			try {
				System.out.println("线程:" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "进入printA");
				Thread.sleep(3000);
				System.out.println("线程:" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "离开printA");
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
		}

	}

	static public void printB() {
		synchronized (Service4.class) {
			System.out.println("线程:" + Thread.currentThread().getName() + "在"
					+ System.currentTimeMillis() + "进入printB");
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
			System.out.println("线程:" + Thread.currentThread().getName() + "在"
					+ System.currentTimeMillis() + "离开printB");
		}
	}

}

   运行结果如下:synchronized(class)代码块的作用和synchronized static的作用是一样的

   以前我说过,synchronized还可以传入其他的实例对象或者方法的形参,那么我现在要说一种把synchronized(class)和String一起使用的特殊情况,还是用代码讲解,下面我附上一段代码,如下: 
	public static void main(String[] args) {

		Service5 service = new Service5();
		ThreadA a = new ThreadA(service);
		a.setName("A");
		a.start();
		ThreadB b = new ThreadB(service);
		b.setName("B");
		b.start();
	}

	public static class ThreadB extends Thread {
		private Service5 service;

		public ThreadB(Service5 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			service.print("AA");
		}
	}

	public static class ThreadA extends Thread {
		private Service5 service;

		public ThreadA(Service5 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			service.print("AA");
		}
	}
}

class Service5 {
	public static void print(String string) {

		try {
			synchronized (string) {
				while (true) {

					System.out.println(Thread.currentThread().getName());
					Thread.sleep(1000);
				}
			}

		} catch (InterruptedException e) {

			e.printStackTrace();
		}

	}
}
   运行结果如下:可以看到输出结果会打印出无数个连续的A,这是由于在JVM中有String常量池缓存的功能,所以说printA()和printB()两个方法里传进来的“AA”是同一个值,因此两个线程持有相同的锁,所以总有一个线程执行不到。

  

上面已经看到了常量池带来的问题,因此大多情况下,都不用String最为对像锁,而改用其他的,比如new Object()实例化一个Object对象。可以看看下面的例子,运行后的区别在哪,如下:

	public static void main(String[] args) {

		Service6 service = new Service6();
		ThreadA a = new ThreadA(service);
		a.setName("A");
		a.start();
		ThreadB b = new ThreadB(service);
		b.setName("B");
		b.start();
	}

	public static class ThreadB extends Thread {
		private Service6 service;

		public ThreadB(Service6 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			service.print(new Object());
		}
	}

	public static class ThreadA extends Thread {
		private Service6 service;

		public ThreadA(Service6 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			service.print(new Object());
		}
	}
}

class Service6 {
	
	public static void print(Object object) {

		try {
			synchronized (object) {
				while (true) {

					System.out.println(Thread.currentThread().getName());
					Thread.sleep(1000);
				}
			}

		} catch (InterruptedException e) {

			e.printStackTrace();
		}

	}
}

   运行结果如下:可以看到运行结果是交叉的异步的,说明两个线程持有的锁不是同一把锁。

   

优质内容筛选与推荐>>
1、【生生不息原创】自己动手写Web自动化测试框架6 - 自动化测试框架的规划
2、JS常用小技巧
3、Visual C++ 6.0 插件系列介绍
4、洛谷 P1825 [USACO11OPEN]玉米田迷宫Corn Maze
5、myeclipse 2013 SR2 安装svn


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn