java线程中的synchronized同步关键字

  java线程中的synchronized同步关键字

直接po代码和截图

源码点这里

Person类

package com.demo.thread3;

//Person类
public class Person {

}

TestSynchronized类

package com.demo.thread3;

//测试synchronized()同步块的小括号中可以放什么?
public class TestSynchronized {
	
	String address = "江西省赣州市于都县";
	double salary = 16500.66;

	public static void main(String[] args) {

		// synchronized()的小括号中可以放引用类型(即对象类型),但是不能放基本数据类型
	}

	public void hi() {
		int age = 6;
		// synchronized(基本数据类型)会报错,连编译都通不过
		// synchronized(age){
		// System.out.println("测试同步块######");
		// }
	}
	
	public void hi2() {
//		 synchronized(基本数据类型)会报错,连编译都通不过
//		 synchronized(salary){
//		 System.out.println("测试同步块------");
//		 }
	}

	public void hello() {
		// synchronized(当前对象)
		synchronized (this) {
			System.out.println("测试同步块1");
		}
	}

	public void hello2() {
		String testName = "令狐冲";
		// synchronized(字符串类型对象)
		synchronized (testName) {
			System.out.println("测试同步块2");
		}
	}

	public void hello3() {
		//自定义的Person类
		Person person = new Person();
		// synchronized(自定义类型对象)
		synchronized (person) {
			System.out.println("测试同步块3");
		}
	}

	public void hello4() {
		// synchronized(自定义类型对象)
		synchronized (new Person()) {
			System.out.println("测试同步块4");
		}
	}

	public void hello5() {
		// synchronized(字符串类型对象)
		synchronized (new String("张无忌")) {
			System.out.println("测试同步块5");
		}
	}

	public void hello6() {
		// synchronized(Integer类型对象)
		Integer number = 666;
		synchronized (number) {
			System.out.println("测试同步块6");
		}
	}

	public void hello7() {
		//定义一个int数组(数组也是引用类型,即对象类型)
		int[] score = { 66, 88 };
		// synchronized(数组类型对象)
		synchronized (score) {
			System.out.println("测试同步块7");
		}
	}
	
	public void hello8() {
		// synchronized(类中的属性),该属性必须是引用类型
		synchronized (this.address) {
			System.out.println("测试同步块8");
		}
	}
	
	public void hello9() {
		// synchronized(类中的属性),该属性必须是引用类型
		synchronized (address) {
			System.out.println("测试同步块9");
		}
	}

}

TestSynchronized2类

package com.demo.thread3;

//测试synchronized同步块和synchronized同步方法
public class TestSynchronized2 {
	private String name = "韦小宝";
	private String id = "8866";
	
	/**
	 * 同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很
	 * 明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越
	 * 差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
	 * 
	 * 同步代码块可以用更细粒度的控制锁
	 */

	/**
	 * 如果你有一个TestSynchronized2对象 你想在多线程下同时修改Name和id, 如果你两个set方
	 * 法都声明为同步方法,那么在同一时间只能修改name或者id. 但是这两个是可以同时修改的,所以你需要使用同
	 * 步代码块,将信号量分别设置成name和id.
	 */

	//同步代码块可以用更细粒度的控制锁,比如下面两个set方法
	public void setName(String name) {
		synchronized (name) {
			this.name = name;
		}
	}

	public void setId(String id) {
		synchronized (id) {
			this.id = id;
		}
	}
	
	/**
	 *如果像下面的写法,在方法上加synchronized同步关键字,那么在同一时
	 *间只能有一个线程修改name或者id,很明显,这样做不太好,也不太合理
	 *所以,建议使用上面的synchronized同步块的方式
	 */
	public synchronized void setName2(String name) {
			this.name = name;
	}

	public synchronized void setId2(String id) {
			this.id = id;
	}
	
	
	/**
	 *如下3个方法
	 *synchronized(对象)同步块后面的小括号中,可以放任何对象,只要是引用类型(即对象类型)就可以,
	 *所以synchronized同步块比较灵活,没有局限性(同步块后面需要传递同
	 *步的对象,所以同步块的好处就是,可以指定更多的对象享受同步的优势),而不像同步方法那样只
	 *有包含相关代码的对象受益(即,同步方法写在哪个类中,哪个类的对象才能有同步的功能,所以同步方法相
	 *对于同步块来说,有局限性,所以,我个人建议大家使用同步块)
	 */
	
	//测试synchronized()同步块的小括号中可以放什么?
	// synchronized()的小括号中可以放引用类型(即对象类型),但是不能放基本数据类型
	public void test1() {
		// synchronized(自定义类型对象)
		synchronized (new Person()) {
			System.out.println("测试同步块1");
		}
	}

	public void test2() {
		// synchronized(字符串类型对象)
		synchronized (new String("江西省赣州市于都县")) {
			System.out.println("测试同步块2");
		}
	}

	public void test3() {
		// synchronized(Integer类型对象)
		Integer number = 666;
		synchronized (number) {
			System.out.println("测试同步块3");
		}
	}
	
	// synchronized()的小括号中可以放引用类型(即对象类型),但是不能放基本数据类型
	public void test4() {
		int age = 12;
		// synchronized(基本数据类型)会报错,连编译都通不过
		// synchronized(age){
		// System.out.println("测试同步块4");
		// }
	}
	
	public static void main(String[] args) {

	}

}

SynObj类

package com.demo.thread3;

public class SynObj {
	public synchronized void methodA() {
		//只要进入了methodA()函数,就意味着对象锁住了
		System.out.println("methodA....." + Thread.currentThread() + " " + Thread.currentThread().getName());
		try {
			// sleep()方法导致了线程暂停执行指定的时间,让出cpu给其他线程,
			// 但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
			// 在调用sleep()方法的过程中,线程不会释放对象锁。
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("我是methodA()函数");
	}

	public void methodB() {
		synchronized (this) {
			System.out.println("methodB....." + Thread.currentThread() + " " + Thread.currentThread().getName());
		}
	}

	public void methodC() {
		String str = "江西省赣州市于都县";
		synchronized (str) {//synchronized(str)这句话中的小括号中放的是String字符串对象
			System.out.println("methodC....." + Thread.currentThread() + " " + Thread.currentThread().getName());
		}
	}

	public void methodD() {
		System.out.println("methodD....." + Thread.currentThread() + " " + Thread.currentThread().getName());
		try {
			// sleep()方法导致了线程暂停执行指定的时间,让出cpu给其他线程
			Thread.sleep(5000);//执行这句话的时候,还没锁,也就意味着,此时其他线程可以执行同一个对象的另一个同步方法
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//使用同步块,可以减小线程同步的粒度,线程同步的粒度越小越好,即线程同步的代码块越小越好
		 /*
		  * 同步代码块可以用更细粒度的控制锁,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越
		  * 大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
		  */
		synchronized (this) {//执行了这句话的时候,才开始锁
			System.out.println("我是methodD()函数中的synchronized同步块");
		}
		System.out.println("我是methodD()函数");
	}

	public synchronized void methodE() {
		System.out.println("methodE....." + Thread.currentThread() + " " + Thread.currentThread().getName());
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("我是methodE()函数");
	}

	public void methodF() {
		System.out.println("methodF....." + Thread.currentThread() + " " + Thread.currentThread().getName());
		synchronized (this) {
			System.out.println("我是methodF()函数中的synchronized同步块");
		}
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("我是methodF()函数");
	}

	public synchronized void methodG() {
		System.out.println("我是一个同步方法methodG....." + Thread.currentThread() + " " + Thread.currentThread().getName());
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("我是methodG()函数,我是一个同步方法");
	}

	public synchronized void methodH() {
		System.out.println("我是methodH()函数,我是一个同步方法");
	}

	public void methodJ() {
		System.out.println("我是methodJ()函数,我是一个普通方法");
	}
}

TestSyn类

package com.demo.thread3;

public class TestSyn {
	/**
	 * 测试后,最终运行的结果是打印出如下:
	 * methodA.....
	 * methodC...
	 * 下面这2句话要隔几秒钟才会打印出来
	 * 我是methodA()函数
	 * methodB.....
	 */
	
	public static void main(String[] args) {
		/**
		 * 分析运行过程如下,供大家参考:
		 * 启动线程1调用方法methodA后,会打印出methodA.....
		 * 接着会让线程1休眠5秒钟,
		 * 这时会调用方法methodC,注意到方法methodC这里用synchronized进行加锁,这里锁的对象是str这个字符串对象,
		 * 所以此时会打印出methodC.....
		 * 但是方法methodB则不同,是用当前对象this进行加锁,方法methodA直接在方法上加synchronized关键字,
		 * 显然,methodB和methodA这两个方法用的是同一把锁
		 * 显然,在methodA同步方法中,在调用sleep()方法的过程中,线程不会释放对象锁
		 * 当线程1指定的5秒钟时间到了,又会自动恢复运行状态,此时打印出我是methodA()函数,
		 * 当线程1的methodA()同步方法执行完毕后,此时会释放掉锁,此
		 * 时才会执行线程2中的methodB方法,此时打印出methodB.....
		 * 
		 * 由此可知,在methodA方法上加synchronized同步关键字和在methodB方
		 * 法内加synchronized同步块, 这两种加锁机制用的是同一个锁对象,即当前对象
		 * 
		 * 所以,最终运行的结果是
		 * methodA.....
		 * methodC...
		 * 下面这2句话要隔几秒钟才会打印出来
		 * 我是methodA()函数
		 * methodB.....
		 */
		
		/**
		 * 同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很
		 * 明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越
		 * 差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
		 * 
		 * 同步代码块可以用更细粒度的控制锁
		 */
		final SynObj obj = new SynObj();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodA();
			}
		});
		t1.start();

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodB();
			}
		});
		t2.start();

		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodC();
			}
		});
		t3.start();
	}
}

运行结果如下:

TestSyn2类

package com.demo.thread3;

public class TestSyn2 {
	public static void main(String[] args) {
		final SynObj obj = new SynObj();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodD();
			}
		});
		t1.start();

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodB();
			}
		});
		t2.start();

		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodC();
			}
		});
		t3.start();
	}

}

运行结果如下:

TestSyn3类

package com.demo.thread3;

public class TestSyn3 {
	public static void main(String[] args) {
		final SynObj obj = new SynObj();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodF();
			}
		});
		t1.start();

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodB();
			}
		});
		t2.start();

		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodC();
			}
		});
		t3.start();
	}

}

运行结果如下:

TestSyn4类

package com.demo.thread3;

public class TestSyn4 {
	public static void main(String[] args) {
		final SynObj obj = new SynObj();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodE();
			}
		});
		t1.start();

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodB();
			}
		});
		t2.start();

		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodC();
			}
		});
		t3.start();
	}

}

运行结果:

TestSyn5类

package com.demo.thread3;

public class TestSyn5 {
	public static void main(String[] args) {
		final SynObj obj = new SynObj();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodG();
			}
		});
		t1.start();

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodH();
			}
		});
		t2.start();

		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodJ();
			}
		});
		t3.start();
	}

}

运行结果:

TestSyn6类

package com.demo.thread3;

public class TestSyn6 {
	public static void main(String[] args) {
		final SynObj obj = new SynObj();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodF();
			}
		});
		t1.start();

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodB();
			}
		});
		t2.start();

		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodG();
			}
		});
		t3.start();
	}

}

运行结果:

TestSyn7类

package com.demo.thread3;

public class TestSyn7 {
	public static void main(String[] args) {
		final SynObj obj = new SynObj();

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodD();
			}
		});
		t1.start();

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodH();
			}
		});
		t2.start();

		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				obj.methodJ();
			}
		});
		t3.start();
	}

}

运行结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值