线程间数据共享

线程间的数据共享(共享同一个对象,对象锁)


文章目录

        一、并发运行

        二、串行运行

        三、多线程的同步原理

        四、死锁


一、并发运行

默认情况下线程是并发运行(指一个时间段中多个线程都处于已启动但没有运行结束的状态),抢占CPU 执行权,这种运行方式往往会出现交叉的情况。这种运行方式往往会出现交叉的情况

实例

public class Test {

	public static void main(String[] args) {
		new CounterThread("线程1").start();
		new CounterThread("线程2").start();//抢占式运行,运行结果会出现交叉的情况
	}
}

class CounterThread extends Thread{

	public CounterThread(String threadName){
		super(threadName);
	}
	
	@Override
	public void run() {
		for(int i=0;i<3;i++){
			System.out.println(getName()+" : "+i);
		}
	}
}

运行结果

线程间数据共享_第1张图片

二、串行运行

为了避免交叉的情况,使一个线程结束了另一个线程才执行,即串行运行,需要通过对象锁机制来实现,synchronized就是一个利用锁实现线程同步的关键字

实例

public class Test {

	public static void main(String[] args) {
		Object showData = new Object();//多线程之间的数据共享
		new CounterThread("线程1",showData).start();
		new CounterThread("线程2",showData).start();//抢占式运行,运行结果会出现交叉的情况
	}
}

class CounterThread extends Thread{
	
	private Object showData;
	public CounterThread(String threadName,Object showData){
		super(threadName);
		this.showData=showData;
	}
	
	@Override
	public void run() {
		synchronized (showData) {//临界区,统一时间只允许一个线程执行里面的代码
			for (int i = 0; i < 3; i++) {
				System.out.println(getName() + " : " + i);
			}
		}
	}
}

运行结果

线程间数据共享_第2张图片

showData是一个对象锁,该对象可由任意类创建,只要求所创建的对象在多个线程之间共享即可

三、多线程的同步原理

为什么通过synchronized就能实现多线程间行运行呢?

synchronized括着的部分就是线程执行临界区,每次仅能有一个线程执行该临界区中的代码:当多个线程中的某个线程先拿到对象锁, 则该线程执行临界区内的代码,其他线程只能在临界区外部等待,当此线程执行完临界区中的代码后,在临界区外部等待的其他线程开始再次竞争以获取对象锁,进而执行临界区中的代码,但只能有一条线程“胜利”。

临界区中的代码具有互斥性、唯一性和排它性:一个线程只有执行完临界区中的代码另一个线程才能执行。

实例1

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(60000);
			} 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);//为什么这行代码60秒左右才会执行?
			//显示器线程和时间线程共享lockObj对象,显示器线程优先进入启动状态,随后执行相应的run方法,当执行同步代码块时lockObj变量所代表的对象锁归显示器线程所有,
			//进而创建时间线程并使之处于启动状态,此时有一下两种状态:
			//1、时间线程马上进入执行状态,
			//马上执行该时间线程run方法,可是由于此时lockObj变量所代表的对象锁被显示器线程持有,
			//这时时间线程进入阻塞状态,显示器线程再次执行,然后执行sleep方法,显示器线程在继续持有对象锁的前提下
			//也进入阻塞状态,60秒后显示器线程进入执行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行;
			//2、时间线程并没有马上进入执行状态,显示器线程执行sleep方法,显示器线程在继续持有对象锁的前提下
			//也进入阻塞状态,此时时间线程进入执行状态,执行该时间线程run方法,执行该方法中第一行输出代码,
			//可是由于此时lockObj变量所代表的对象锁被显示器线程持有,
			//所以时间线程并没有执行时间线程run方法内临界区中的代码,这时时间线程也进入阻塞状态,此时显示器和时间两条线程均进去阻塞状态,
			//等待少于60秒的时间后,显示器线程进入运行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行;
		}
	}
}

结果:

线程间数据共享_第3张图片

实例2

public class Test {
	public static void main(String[] args) {
		new CountThread().start();
		new CountThread().start();
	}
}

class CountThread extends Thread{
	
	static Object object = new Object();//该对象能在多个线程之间共享吗?由于是静态的,程序一执行该对象就创建,是唯一的,因此可以在线程间共享,如果是Object object = new Object()就不可以,每个线程都会创建一个新的Object的对象,因此不共享
	
	@Override
	public void run() {
		synchronized (object) {
			for (int i = 1; i <= 10; i++) {
				System.out.println(getName() + "--->" + i);
			}
		}
	}
}

结果:

线程间数据共享_第4张图片

实例3

public class Test {
	public static void main(String[] args) {
		new CountThread().start();
		new CountThread().start();
	}
}

class CountThread extends Thread{
	
	Object object = new Object();//Object object = new Object()就不可以,每个线程都会创建一个新的Object的对象,因此不共享
	
	@Override
	public void run() {
		synchronized (object) {
			for (int i = 1; i <= 10; i++) {
				System.out.println(getName() + "--->" + i);
			}
		}
	}
}

结果:

线程间数据共享_第5张图片

实例4

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

}

class CountThread extends Thread{
	public CountThread(String name) {
		super(name);
	}
	
	@Override
	public void run() {
		synchronized ("") {//""在常量池里面,是唯一的,可以实现数据间的共享
			for (int i = 0; i < 100; i++) {
				System.out.println(getName() + "," + new Date());
			}
		}
	}
	
//	@Override
//	public void run() {
//		synchronized (String.class) {//生成class对象的构造方法是私有的,是单例,可以实现线程间的数据共享
//			for (int i = 0; i < 100; i++) {
//				System.out.println(getName() + "," + new Date());
//			}
//		}
//	}
	
//	@Override
//	public void run() {
//		synchronized (this) {//不可以,this代表执行它的对象(即CountThread对象),在这里不共享
//			for (int i = 0; i < 100; i++) {
//				System.out.println(getName() + "," + new Date());
//			}
//		}
//	}
	
//	@Override
//	public synchronized void run() {//与synchronized (this)等同,共享的不是同一个对象,因此不能实现串行执行
//			for (int i = 0; i < 100; i++) {
//				System.out.println(getName() + "," + new Date());
//			}
//	}	
}

实例5

public class Test {//不同类线程共用同一个对象锁,实现串行
	
	public static void main(String[] args) {
		Object object= new Object();
		new CountThread("************",object).start();
		new TimeThread("############",object).start();
	}

}

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

class TimeThread extends Thread{
	
	Object object = new Object();
	
	public TimeThread(String name,Object object) {
		super(name);
		this.object = object;
	}
	
	@Override
	public void run() {
		synchronized (object) {
			for (int i = 0; i < 200; 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");
				}
			}
		}
	}
}

 

你可能感兴趣的:(线程间数据共享)