Java中详述详述线程间数据共享

本文介绍了Java中并发运行与串行运行的概念,通过示例展示了线程交叉执行的问题及解决方案。使用`synchronized`关键字实现线程同步,避免交叉执行。同时,解释了死锁现象,并提供了死锁的例子。最后,分析了多线程同步的原理,解释了在特定情况下代码执行的延迟原因。
摘要由CSDN通过智能技术生成

并发运行与串行运行

多个线程之间默认并发运行,这种运行方式往往会出现交叉的情况。首先引入一段代码来说明这种情况:

package 线程间数据共享;

public class Test {

	public static void main(String[] args) {
		new CountThread("@@@@").start();
		new CountThread("###############").start();		
	}
	
}

class CountThread extends Thread{
	CountThread(String name){
		super(name);
	}
	
	@Override
	public void run() {
		for(int i = 0;i<50;++i) {
			System.out.println(getName()+","+i);
		}
	}
}

结果显示为:
在这里插入图片描述

synchronized关键字

synchronized同步关键字有两种使用方式:
1、声明同步方法:

public synchronized void methodName( ){
	同步操作方法体
}

2、同步代码块:

synchronized (需要同步操作的对象) {
	      同步对象操作的语句
}

线程默认情况下以抢占式执行,因此会出现交叉执行的情况,如何解决交叉执行的问题。不强调谁先谁后,但是强调只有一个线程执行结束才执行下一个线程。因此,我们通过synchronized关键字对代码进行修改:

package 线程间数据共享;

public class Test {

	public static void main(String[] args) {
		Object object = new Object();
		new CountThread("@@@@",object).start();
		new CountThread("###############",object).start();
	}
	
}

class CountThread extends Thread{
	
	Object object;
	
	CountThread(String name,Object object){
		super(name);
		this.object=object;
	}
	
	@Override
	public void run() {
		synchronized(object) {
			for(int i = 0;i<50;++i) {
				System.out.println(getName()+","+i);
			}
		}
	}
}

结果显示为:
在这里插入图片描述
由此可以看出,通过synchronized和object对象来进行限定,从而实现了线程的依次执行,只不过执行顺序的先后没有规定。synchronized临界区中的代码,只可有且仅有一个线程执行。其中object->""或xxx.class的形式也可以解决交叉执行。
但是,当synchronized出现在方法体中,则无法避免交叉执行:

@Override
public void run() {
	synchronized(this) {
		for(int i = 0;i<50;++i) {
			System.out.println(getName()+","+i);
		}
	}
}

或者

@Override
	public synchronized void run() {
			for(int i = 0;i<50;++i) {
				System.out.println(getName()+","+i);
			}
	}

结果显示为:
在这里插入图片描述

死锁

如果有两个或两个以上的线程都访问了多个资源,而这些线程占用了一些资源的同时又在等待其它线程占用的资源,也就是说多个线程之间都持有了对方所需的资源,而又相互等待对方释放的资源,在这种情况下就会出现死锁。
多个线程互相等待对方释放对象锁,此时就会出现死锁

public class DeadLockThread {
	// 创建两个线程之间竞争使用的对象
	private static Object lock1 = new Object();
	private static Object lock2 = new Object();

	public static void main(String[] args) {
		new ShareThread1().start();
		new ShareThread2().start();
	}

	private static class ShareThread1 extends Thread {
		public void run() {
			synchronized (lock1) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (lock2) {
					System.out.println("ShareThread1");
				}
			}
		}
	}

	private static class ShareThread2 extends Thread {
		public void run() {
			synchronized (lock2) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (lock1) {
					System.out.println("ShareThread2");
				}
			}
		}
	}
}

结果显示为:
在这里插入图片描述
我们可以看到光标浮动,但是没有结果输出。

多线程同步原理

代码展示为:

package 线程间数据共享;

import java.text.*;
import java.util.Date;

public class Test {

	public static void main(String[] args) {
		Object lockObj = new Object();
		new DisplayThread(lockObj).start();
	}
}

class DisplayThread extends Thread {

	Object lockObj;

	public DisplayThread(Object lockObj) {
		this.lockObj = lockObj;
	}

	@Override
	public void run() {
		synchronized (lockObj) {
			new TimeThread(lockObj).start();
			try {
				sleep(10000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
class TimeThread extends Thread {

	Object lockObj;

	public TimeThread(Object lockObj) {
		this.lockObj = lockObj;
	}

	@Override
	public void run() {
		System.out.println("时间线程开始执行......"+new Date());
		synchronized (lockObj) {
			DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
			String time = dateFormat.format(new Date());
			System.out.println(time);//为什么这行代码10秒左右才会执行?
		}
	}
}

结果显示为:
在这里插入图片描述
从结果可以看出,执行输出时间的代码与输出“时间线程开始执行”的代码之间相差了10s。
为什么这行代码10秒左右才会执行?
显示器线程和时间线程共享lockObj对象,显示器线程优先进入启动状态,随后执行相应的run方法,当执行同步代码块时lockObj变量所代表的对象锁归显示器线程所有,进而创建时间线程并使之处于启动状态,此时有一下两种状态:
1、时间线程马上进入执行状态,马上执行该时间线程run方法,可是由于此时lockObj变量所代表的对象锁被显示器线程持有,这时时间线程进入阻塞状态,显示器线程再次执行,然后执行sleep方法,显示器线程在继续持有对象锁的前提下也进入阻塞状态,10秒后显示器线程进入执行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行;
2、时间线程并没有马上进入执行状态,显示器线程执行sleep方法,显示器线程在继续持有对象锁的前提下也进入阻塞状态,此时时间线程进入执行状态,执行该时间线程run方法,执行该方法中第一行输出代码,可是由于此时lockObj变量所代表的对象锁被显示器线程持有,所以时间线程并没有执行时间线程run方法内临界区中的代码,这时时间线程也进入阻塞状态,此时显示器和时间两条线程均进去阻塞状态,等待少于10秒的时间后,显示器线程进入运行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值