访问同步方法的7种情况
1.两个线程同时访问一个对象的同步方法
两个不同的实例,访问同一个对象的同步方法,所运用的锁默认使用的是this,以this对象作为他的锁,所以说,他们使用的是同一把锁,在争抢同一把锁的时候,他们必然要相互等待,因为只能有一个方法持有锁
代码如下:
package com.gwh.lock.test;
/**
* 对象锁 实例2 方法锁形式
* 1.两个线程同时访问一个对象的同步方法
*/
public class SynchronizedObjectMethod3 implements Runnable{
public static SynchronizedObjectMethod3 objectMethod3=new SynchronizedObjectMethod3();
@Override
public void run() {
method();
}
public synchronized void method(){
System.out.println("我是对象锁的方法修饰符形式,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public static void main(String[] args) {
try {
Thread t1=new Thread(objectMethod3);
Thread t2=new Thread(objectMethod3);
t1.start();
t2.start();
while (t1.isAlive()||t2.isAlive()){
}
System.out.println("finished");
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下
2.两个线程访问的是两个对象的同步方法
两个线程访问的是两个对象的同步方法,他们之间是不会受到干扰的,原因是,他们真正所使用的锁对象不是同一个,所以不敢扰
代码如下:
package com.gwh.lock.test;
/**
* 对象锁实例1 代码块形式
* 2.两个线程访问的是两个对象的同步方法
*/
public class SychronizedObjectCodeBlock2 implements Runnable{
public static SychronizedObjectCodeBlock2 objectCodeBlock2=new SychronizedObjectCodeBlock2();
//不是用this是因为,可能在同一段代码中,会有多个synchronized代码块,他们不会ishi同时一个执行其他的不执行,所以我们新建一个锁对象
Object lock1=new Object();
Object lock2=new Object();
@Override
public void run() {
//使用锁的对象不同会对执行的结果带来不同的影响
synchronized (lock1){
try {
System.out.println("我是对象锁1的代码块形式,我叫"+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName()+"对象锁1执行结束");
}catch (Exception e){
e.printStackTrace();
}
}
/* synchronized (lock2){
try {
System.out.println("我是对象锁2的代码块形式,我叫"+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName()+"对象锁2执行结束");
}catch (Exception e){
e.printStackTrace();
}
}
*/
}
public static void main(String[] args) {
try {
Thread t1=new Thread(objectCodeBlock2);
Thread t2=new Thread(objectCodeBlock2);
t1.start();
t2.start();
while (t1.isAlive()||t2.isAlive()){
}
System.out.println("finished");
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下:
3.两个线程访问的是Synchronized的静态方法
他们会一个一个的执行,锁生效
代码如下:
package com.gwh.lock.test;
/**
* 类锁的第一种形式,static形式
* 3.两个线程访问的是Synchronized的静态方法
*/
public class SynchronizedClassStatic4 implements Runnable{
public static SynchronizedClassStatic4 classStatic4=new SynchronizedClassStatic4();
public static SynchronizedClassStatic4 classStatic5=new SynchronizedClassStatic4();
@Override
public void run() {
method();
}
public static synchronized void method(){ System.out.println("我是类锁的第一种形式:static形式,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public static void main(String[] args) {
try {
Thread t1=new Thread(classStatic4);
Thread t2=new Thread(classStatic5);
t1.start();
t2.start();
while (t1.isAlive()||t2.isAlive()){
}
System.out.println("finished");
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下:
4.同时访问同步和非同步方法
非同步方法不会受到影响
因为synchronized这个关键字,只会作用于你修饰的一个方法中,他不会影响到没加修饰符的方法
代码如下:
package com.gwh.lock.test;
/**
* 4.同时访问同步和非同步方法
*/
public class SynchronizedYesAndNo6 implements Runnable{
public static SynchronizedYesAndNo6 yesAndNo6=new SynchronizedYesAndNo6();
@Override
public void run() {
if(Thread.currentThread().getName().equals("Thread-0")){
method1();
}else {
method2();
}
}
public synchronized void method1(){
System.out.println("我是加锁的方法,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public void method2(){
System.out.println("我是没加锁的方法,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public static void main(String[] args) {
try {
Thread t1=new Thread(yesAndNo6);
Thread t2=new Thread(yesAndNo6);
t1.start();
t2.start();
while (t1.isAlive()||t2.isAlive()){
}
System.out.println("finished");
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下
5.访问一个对象的不同的普通同步方法(非static)
synchronized虽然没有明确指定使用哪个锁对象,但是他本质上是指定了this作为他的锁,所以对于同一个实例来讲,这两个方法所使用的this是一样的,所以这两个方法没法同时运行
代码如下:
package com.gwh.lock.test;
/**
* 访问一个类的不同的普通同步方法
*/
public class synchronizedDifferentMethod7 implements Runnable{
public static synchronizedDifferentMethod7 differentMethod7=new synchronizedDifferentMethod7();
@Override
public void run() {
if(Thread.currentThread().getName().equals("Thread-0")){
method1();
}else {
method2();
}
}
public synchronized void method1(){
System.out.println("我是加锁的方法,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public synchronized void method2(){
System.out.println("我是加锁的方法,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public static void main(String[] args) {
try {
Thread t1=new Thread(differentMethod7);
Thread t2=new Thread(differentMethod7);
t1.start();
t2.start();
while (t1.isAlive()||t2.isAlive()){
}
System.out.println("finished");
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下:
6.同时访问静态Synchronized和非静态Synchronized方法
两个方法会同时运行,原因是:他们所指定的锁对象,不是同一个锁
代码如下:
package com.gwh.lock.test;
/**
* 同时访问静态Synchronized和非静态Synchronized方法
*/
public class SynchronizedStaticAndNormal8 implements Runnable{
public static SynchronizedStaticAndNormal8 staticAndNormal8=new SynchronizedStaticAndNormal8();
@Override
public void run() {
if(Thread.currentThread().getName().equals("Thread-0")){
method1();
}else {
method2();
}
}
public synchronized static void method1(){
System.out.println("我是静态加锁的方法1,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public synchronized void method2(){
System.out.println("我是非静态的加锁的方法2,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public static void main(String[] args) {
try {
Thread t1=new Thread(staticAndNormal8);
Thread t2=new Thread(staticAndNormal8);
t1.start();
t2.start();
while (t1.isAlive()||t2.isAlive()){
}
System.out.println("finished");
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下:
7.方法抛出异常后,会释放锁
Synchronized修饰的类,抛出异常后会释放锁,lock类抛出异常后,不会释放锁
代码如下:
package com.gwh.lock.test;
/**
* 方法抛出异常后,会释放锁。展示不抛出异常前,和抛出异常后的对比
* 一旦抛出了异常,第二个线程会立刻进入同步方法,意味着锁已经释放
*/
public class SynchronizedException9 implements Runnable{
public static SynchronizedException9 exception9=new SynchronizedException9();
@Override
public void run() {
if(Thread.currentThread().getName().equals("Thread-0")){
method1();
}else {
method2();
}
}
public synchronized void method1(){
System.out.println("我是方法1,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
throw new Exception();
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public synchronized void method2(){
System.out.println("我是方法2,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行结束");
}
public static void main(String[] args) {
try {
Thread t1=new Thread(exception9);
Thread t2=new Thread(exception9);
t1.start();
t2.start();
while (t1.isAlive()||t2.isAlive()){
}
System.out.println("finished");
}catch (Exception e){
e.printStackTrace();
}
}
}
结果如下: 总结: 1.一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待
2.每个实例都对应有自己的一把锁,不同实例之间互不影响;例外:锁对象是*.class以及Synchronized修饰的是static方法的时候,所有对象共用同一把类锁
3.无论是方法正常执行完毕或者是方法抛出异常,都会释放锁
问题:如果说,我在一个被Synchronized所修饰的方法中,访问一个不被Synchronized修饰的方法时,此时是线程安区的吗?
线程不安全,因为被访问的方法没有被Synchronized所修饰,所以他是会被多个线程共同访问的