Java多线程-2(线程同步synchronized关键字)

为何要实现线程同步

多线程机制的目的是为了能并发执行程序,为何要实现线程间同步,使其看起来像是让每个线程按顺序执行呢?答案是:当线程之间没有“相交点”(共享资源)时,不需要线程同步,但是当操作某个线程间共享资源(如静态变量),就需要实现线程同步。

java提供的线程同步机制

一.synchronized关键字

1.当synchronized关键字修饰方法

  • a.大部分人熟悉的线程同步方式是上锁,而synchronized关键字实现同步的方式其实也是上锁。那么上锁就是要看给什么东西上锁,是方法还是对象,当synchronized关键字修饰方法时,是给调用该方法的对象上的锁(因为一个类有多个对象,通过哪个对象调用的方法就给哪个个对象上锁)。那么这个锁是什么锁呢,是每个对象都拥有的内置锁

  • b.使用synchronized关键字的例子:

/*
*	synMethrod.java文件
*	定义了一个synchronized方法methrod,该方法先打印一次字符串,然后sleep一秒,在打印一次字符串
*/
public class synMethrod{
	public synchronized void methrod(String arg) {
		System.out.println(arg + "start");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(arg + "end");
	}
}

***************************************************************
/*
*	ThradPractice.java文件
*/
import java.lang.*;
import java.util.*;

public class ThreadPractice{
	public static void main(String[] args) {
		synMethrod m = new synMethrod();
		Thread t1 = new MyThread(m,"Thread1");
		Thread t2 = new MyThread(m,"Thread2");
		t1.start();
		t2.start();
	}
}

class MyThread extends Thread{
	private synMethrod m; 
	private String s;
	public MyThread(synMethrod m,String s) {
		this.m = m;
		this.s = s;
	}
	@Override
	public void run() {
		m.methrod(s);	
	}
}

上述代码的运行结果:
在这里插入图片描述
可以看出,在线程1调用methrod方法后,线程2并没有马上进行methord方法,而是等线程1执行完methrod方法后,线程2才执行methrod方法。如果将methrod方法的synchronized关键字去掉,那么程序的运行结果如下:
在这里插入图片描述
可以看出此时线程1和线程2同时进入了methrod方法执行。

注意:对于上述代码,由于在java中,将对象作为参数时,是进行了引用传递,所以在线程1和线程2中的synMethrod对象是同一个对象,synchronized关键字是将该synMethrod对象的内置锁进行上锁

2.当synchronized关键字修饰静态方法
a.静态成员不属于任何对象,那么当synchronized关键字上的锁可以理解为类锁,当synchronized关键字修饰一般成员方法时上的锁可以理解为对象锁,属于某个对象。
b.下面将举一个例子,可以看出“类锁”和“对象锁不冲突”。在synMethrod类中新定义一个静态方法。线程1调用原methrod方法,线程2调用staticMethrod方法。如下:

/*
*	synMethrod.java文件
*	新定义了staticMethrod方法
*/
public class synMethrod{
	public void methrod(String arg) {
		System.out.println(arg + "start");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(arg + "end");
	}
	
	public static synchronized void staticMethord(String arg) {
		System.out.println(arg + "start (static)");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(arg + "end (static)");
	}
}

********************************************************************
/*
*	ThreadPractice.java
*	线程1执行一般成员方法,线程2执行静态成员方法
*/
import java.lang.*;
import java.util.*;

public class ThreadPractice{
	public static void main(String[] args) {
		synMethrod m = new synMethrod();
		Thread t1 = new MyThread(m,"Thread1");
		Thread t2 = new MyThread2(m,"Thread2");
		t1.start();
		t2.start();
		
	}
}

class MyThread extends Thread{
	private synMethrod m; 
	private String s;
	public MyThread(synMethrod m,String s) {
		this.m = m;
		this.s = s;
	}
	@Override
	public void run() {
		m.methrod(s);
	}
}

class MyThread2 extends Thread{
	private synMethrod m; 
	private String s;
	public MyThread2(synMethrod m,String s) {
		this.m = m;
		this.s = s;
	}
	@Override
	public void run() {
		m.staticMethord(s);
	}
}

上述代码的执行结果如下:
在这里插入图片描述
可以看出,线程1和线程2并没有实现同步,证明“类锁”和"对象锁"之间不存在互斥。
如果将static关键字删掉,上述程序运行结果如下:
在这里插入图片描述
从结果可以看出线程1和线程2实现了互斥,因为他们都使用了同一个对象的“对象锁”。

3.synchronized关键字修饰代码块
为了对线程同步进行更加精确地控制,可以synchronized关键字来修饰代码块。而synchronized关键字在修饰代码块时又分为两种类型,即使用“类锁”还是使用“对象锁”。

  • 使用类锁
    语法:
synchronized(类名.class){
//需要进行同步的代码块
}
  • 使用对象锁
    语法
synchronized(this){
//需要进行同步的代码块
}

例子如下:

/*
* synMethrod文件
*/
public class synMethrod{
	public void methrod(String arg) {
		//使用对象锁
		synchronized(this){
			System.out.println(arg + "start");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(arg + "end");
		}
	}
	
	public void staticMethord(String arg) {
		//使用类锁
		synchronized(synMethrod.class) {
			System.out.println(arg + "start (static)");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(arg + "end (static)");
		}
	}
}

总结:使用synchronized关键字进行现场同步时需要理解一下两点
1.synchronized关键字是通过上锁来实现了
2.synchronized关键字使用的锁分为“类锁”和“对象锁”,根据不同使用场景选择不同的锁(即synchronized关键字的使用方式)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 第2要求使用synchronized关键字同步线程synchronized关键字可以用来保证多个线程访问共享资源时的同步性,避免出现数据竞争和不一致的情况。在使用synchronized关键字时,需要指定一个锁对象,多个线程需要使用同一个锁对象才能实现同步。在锁对象上加锁的线程可以进入临界区,其他线程则需要等待锁对象被释放后才能进入临界区。这样可以保证同一时刻只有一个线程访问共享资源,从而避免了数据竞争和不一致的情况。 ### 回答2: 在多线程环境下,线程之间可能会出现资源竞争的情况,也就是多个线程同时尝试访问同一个资源,从而造成数据不一致或者程序崩溃等问题。为了避免这种情况的发生,Java提供了synchronized关键字同步线程,保证线程安全。 在使用synchronized关键字同步线程的时候,需要注意以下几点: 1. synchronized可以用在方法或者代码块中,用来锁定对象或者类。在锁定对象的情况下,不同线程可以同时执行不同对象的非同步方法,但是同一对象的同步方法只能由一个线程执行。 2. synchronized锁定的对象不能是null,需要注意空指针异常问题。 3. synchronized关键字会给代码块或方法加上一个监视器,也就是锁。在进入synchronized方法或代码块之前,线程必须先获得锁,获得锁之后才能执行方法或代码块中的内容。 4. 当线程执行完synchronized方法或者代码块中的内容后,会自动释放锁,其他线程可以继续竞争锁。 在实际应用中,synchronized关键字可以用来解决资源竞争问题,保证线程安全。但是,在竞争激烈的情况下,不同线程之间的抢占锁可能会降低程序的性能,因此需要综合考虑程序的运行效率和线程安全问题。 ### 回答3: synchronized关键字Java中常用的实现线程同步的方法。线程同步是多个线程以一定的顺序访问共享资源,避免线程间的竞争和数据不一致的问题。当多个线程同时访问一个共享资源时,使用synchronized关键字可以保证同一时刻只有一个线程在执行相应的代码块,从而保证数据的正确性和安全性。 synchronized关键字可以用于方法和代码块中。当关键字修饰方法时,该方法被称为同步方法,当关键字修饰代码块时,该代码块被称为同步代码块。 在实现线程同步时,使用synchronized关键字可以避免多个线程同时访问同一个共享资源,从而产生数据不一致的问题。使用synchronized关键字可以让一个线程在进入synchronized代码块之前获得锁,并在代码块执行完毕之后释放锁。在Java中,每个对象都有一个内部锁,也称为监视器锁。当一个线程访问synchronized代码块时,它必须先获得对象的监视器锁,才能进入该代码块执行。 当一个线程获得了对象的监视器锁时,其他线程必须等待该线程执行完毕并释放锁之后才能进入代码块执行。这样就保证了同一时刻只有一个线程在执行代码块,从而保证了数据的一致性和正确性。 总之,使用synchronized关键字可以非常有效地实现线程同步,避免了多个线程并发访问共享资源时产生的数据不一致问题。它是Java中实现线程同步的常用方法之一,也是Java多线程编程中非常重要的一个知识点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值