线程数据共享与协作

线程数据共享

  • 数据(即任意的对象)在多个线程之间的共享

方式一:构造方法传入共享数据(对象)

测试类

public class ThreadShareDataTest {
	public static void main(String[] args) {
		Object object = new Object();
		NewThread newThread1 = new NewThread(object);
		NewThread newThread2 = new NewThread(object);
		newThread1.start();
		newThread2.start();
	}
}

线程类

class NewThread extends Thread{
	Object object;
	public NewThread(Object object) {
		this.object = object;
	}
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(getName() + object + "--->" + i);
		}
	}
}

结果:在两个线程之间是同一个对象,这样就实现了数据的共享

Thread-0java.lang.Object@2b8a94a4—>0
Thread-1java.lang.Object@2b8a94a4—>0
Thread-0java.lang.Object@2b8a94a4—>1
Thread-1java.lang.Object@2b8a94a4—>1
Thread-0java.lang.Object@2b8a94a4—>2
Thread-1java.lang.Object@2b8a94a4—>2
Thread-1java.lang.Object@2b8a94a4—>3
Thread-1java.lang.Object@2b8a94a4—>4
Thread-0java.lang.Object@2b8a94a4—>3
Thread-1java.lang.Object@2b8a94a4—>5
Thread-0java.lang.Object@2b8a94a4—>4
Thread-1java.lang.Object@2b8a94a4—>6
Thread-0java.lang.Object@2b8a94a4—>5
Thread-0java.lang.Object@2b8a94a4—>6
Thread-0java.lang.Object@2b8a94a4—>7
Thread-1java.lang.Object@2b8a94a4—>7
Thread-0java.lang.Object@2b8a94a4—>8
Thread-1java.lang.Object@2b8a94a4—>8
Thread-0java.lang.Object@2b8a94a4—>9
Thread-1java.lang.Object@2b8a94a4—>9


方式二:在线程类中定义静态成员变量

  • 在线程类中定义一个静态的成员变量,可以通过类名给变量赋值

测试类

public class ThreadShareDataTest {
	public static void main(String[] args) {
		NewThread newThread1 = new NewThread();
		NewThread newThread2 = new NewThread();
		NewThread newThread3 = new NewThread();
		ExecutorService executorService = Executors.newFixedThreadPool(2);
		executorService.submit(newThread1);
		executorService.submit(newThread2);
		executorService.submit(newThread3);
		executorService.shutdown();
	}
}

线程类

class NewThread extends Thread{
	static Object object = new Object();
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(currentThread().getName()+ "--->" + getName() + "--->" + object + "--->" + i);
		}
	}
}

结果

pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>0
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>0
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>1
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>2
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>1
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>3
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>2
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>4
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>3
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>4
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>5
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>5
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>6
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>7
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>8
pool-1-thread-2—>Thread-1—>java.lang.Object@309d7a5a—>9
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>6
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>0
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>7
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>8
pool-1-thread-1—>Thread-0—>java.lang.Object@309d7a5a—>9
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>1
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>2
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>3
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>4
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>5
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>6
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>7
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>8
pool-1-thread-2—>Thread-2—>java.lang.Object@309d7a5a—>9


synchronized

  • 上面打印出的结果有交叉执行的现象,为了使原本并发运行的多个线程实现串行运行,即多线程间同步执行,需要通过对象锁机制来实现,synchronized就是一个利用锁实现线程同步的关键字。

对需要同步的代码,使用synchronized环绕

class NewThread extends Thread{
	Object lock;
	public NewThread(Object lock) {
		this.lock = lock;
	}
	@Override
	public void run() {
		//lock变量就是共享的数据
		synchronized (lock) {
			for (int i = 0; i < 10; i++) {
				System.out.println(getName() + "--->" + lock + "--->" + i);
			}
		}
	}

测试类

public class ThreadShareDataTest {
	public static void main(String[] args) {
		Object lock = new Object();
		NewThread newThread1 = new NewThread(lock);
		NewThread newThread2 = new NewThread(lock);
		NewThread newThread3 = new NewThread(lock);
		newThread1.start();
		newThread2.start();
		newThread3.start();
	}
}

结果

Thread-0—>java.lang.Object@434e2b1d—>0
Thread-0—>java.lang.Object@434e2b1d—>1
Thread-0—>java.lang.Object@434e2b1d—>2
Thread-0—>java.lang.Object@434e2b1d—>3
Thread-0—>java.lang.Object@434e2b1d—>4
Thread-0—>java.lang.Object@434e2b1d—>5
Thread-0—>java.lang.Object@434e2b1d—>6
Thread-0—>java.lang.Object@434e2b1d—>7
Thread-0—>java.lang.Object@434e2b1d—>8
Thread-0—>java.lang.Object@434e2b1d—>9
Thread-1—>java.lang.Object@434e2b1d—>0
Thread-1—>java.lang.Object@434e2b1d—>1
Thread-1—>java.lang.Object@434e2b1d—>2
Thread-1—>java.lang.Object@434e2b1d—>3
Thread-1—>java.lang.Object@434e2b1d—>4
Thread-1—>java.lang.Object@434e2b1d—>5
Thread-1—>java.lang.Object@434e2b1d—>6
Thread-1—>java.lang.Object@434e2b1d—>7
Thread-1—>java.lang.Object@434e2b1d—>8
Thread-1—>java.lang.Object@434e2b1d—>9
Thread-2—>java.lang.Object@434e2b1d—>0
Thread-2—>java.lang.Object@434e2b1d—>1
Thread-2—>java.lang.Object@434e2b1d—>2
Thread-2—>java.lang.Object@434e2b1d—>3
Thread-2—>java.lang.Object@434e2b1d—>4
Thread-2—>java.lang.Object@434e2b1d—>5
Thread-2—>java.lang.Object@434e2b1d—>6
Thread-2—>java.lang.Object@434e2b1d—>7
Thread-2—>java.lang.Object@434e2b1d—>8
Thread-2—>java.lang.Object@434e2b1d—>9

虽然可能多次运行的线程的运行顺序可能不同,但是只要在一个线程拿到对象锁之后,其他线程就需要等待,在一个线程执行完之后释放锁之后,再开始另外一个线程。

  • 线程之间数据共享的意义也在于多个线程之间持有的锁对象是同一个对象,这样多个线程就实现了串行执行,不会出现交叉执行的现象,否则多个线程之间持有的锁对象不是同一个对象,将无法串行化。

  • 锁对象其实也可以是Class类对象,使用 类名.class或Class.forName(“全类名”)或者 对象.getClass() 由于Class类的构造方法是私有的,且为单例模式,所以使用类名.class 作为锁对象也是可以的。

线程协作

wait()方法

  • 对象锁调用了wait()方法会使当前持有该对象锁的线程处于线程等待状态同时该线程释放对对象锁的控制权,直到在其他线程中该对象锁调用notify()方法或notifyAll()方法时等待此对象锁的线程才会被唤醒

notify()方法

  • 对象锁调用notify()方法就会唤醒在此对象锁上等待的单个线程

notifyAll()方法

  • 对象锁调用notifyAll()方法就会唤醒在此对象锁上等待的所有线程;调用notifyAll()方法并不会立即激活某个等待线程,它只能撤销等待线程的中断状态,这样它们就能够在当前线程退出同步方法或同步代码块法后与其它线程展开竞争,以争取获得资源对象来执行

线程之间的协作

public class ThreadTogetherWorkTest {
	Date time;
	public static void main(String[] args) {
		ThreadTogetherWorkTest threadTogetherWorkTest = new ThreadTogetherWorkTest();
		TimeThread timeThread =threadTogetherWorkTest.new TimeThread();
		DisplayTimeThread displayTimeThread = threadTogetherWorkTest.new DisplayTimeThread();
		timeThread.start();
		displayTimeThread.start();
		
	}

	class TimeThread extends Thread{
		@Override
		public void run() {
			time = new Date();
		}
	}
	
	class DisplayTimeThread extends Thread{	
		@Override
		public void run() {
			System.out.println(time);
		}
		
	}
}

执行结果
有可能为 (displayTimeThread线程先夺取到了CPU的执行权)

null

或者为(timeThread线程先夺取到了CPU的执行权)

Mon Jul 01 17:26:45 CST 2019

  • 为了一定可以打印出时间信息需要线程之间的协作

方式一

  • 使用join
public class ThreadTogetherWorkTest {
	Date time;
	public static void main(String[] args) {
		ThreadTogetherWorkTest threadTogetherWorkTest = new ThreadTogetherWorkTest();
		TimeThread timeThread =threadTogetherWorkTest.new TimeThread();
		DisplayTimeThread displayTimeThread = threadTogetherWorkTest.new DisplayTimeThread(timeThread);
		timeThread.start();
		displayTimeThread.start();		
	}

	class TimeThread extends Thread{
		@Override
		public void run() {
			time = new Date();
		}
	}
	
	class DisplayTimeThread extends Thread{
		TimeThread timeThread;
		public DisplayTimeThread(TimeThread timeThread) {
			this.timeThread = timeThread;
		}
		
		@Override
		public void run() {
			if(time==null) {
				try {
					timeThread.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(time);
		}
		
	}
}

方式二

  • 使用synchronized执行同步代码块,配合wait和notify方法
public class ThreadTogetherWorkTest {
	Date time;
	public static void main(String[] args) {
		ThreadTogetherWorkTest threadTogetherWorkTest = new ThreadTogetherWorkTest();
		TimeThread timeThread =threadTogetherWorkTest.new TimeThread();
		DisplayTimeThread displayTimeThread = threadTogetherWorkTest.new DisplayTimeThread();
		timeThread.start();
		displayTimeThread.start();
		
	}

	class TimeThread extends Thread{
		@Override
		public void run() {
			time = new Date();
			synchronized (ThreadTogetherWorkTest.class) {
				ThreadTogetherWorkTest.class.notify();
			}
		}
	}
	
	class DisplayTimeThread extends Thread{
		@Override
		public void run() {
			if(time==null) {
				synchronized (ThreadTogetherWorkTest.class) {
					try {
						ThreadTogetherWorkTest.class.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			System.out.println(time);
		}
	}
}

结果

Mon Jul 01 17:34:44 CST 2019

注意:wait方法和sleep方法的区别

  1. wait方法非静态但是是Object的方法;sleep是Thread的静态方法
  2. wait方法要配合synchronized以及notify使用;sleep不需要
  3. 执行wait方法时当前线程进入阻塞状态,并且释放对象锁;执行sleep方法当前线程虽然也会进入阻塞状态,但是并不释放对象锁
### 线程进程的数据共享 #### 线程数据共享的优势和劣势 线程作为同一进程中执行流的部分,能够方便地访问该进程内的全局变量和其他资源。这种特性使得线程间的通信变得简单高效。 - **优势** - 高效性:由于线程属于同一个进程空间,因此可以直接读写相同的内存区域而无需复杂的传递机制[^1]。 - 资源利用率高:减少了因跨进程边界传输所需的时间成本以及额外的缓冲区管理开销[^4]。 - **劣势** - 同步难题:多个线程可能同时尝试修改相同位置的数据,这就要求开发者精心设计锁机制或其他形式的互斥控制来防止竞争条件的发生[^5]。 ```python import threading lock = threading.Lock() def thread_safe_operation(): with lock: # Critical section code here pass ``` #### 进程间数据共享的优势和劣势 相比之下,不同进程之间拥有独立地址空间,默认情况下无法直接相互作用;然而,Linux 提供了几种有效的IPC(Inter-process Communication)手段用于实现安全可靠的信息交换。 - **优势** - 安全隔离度好:每个进程都有自己私有的虚拟地址范围,即使某个子系统崩溃也不会影响到其他部分的工作稳定性。 - 易于调试维护:因为各个组件相对封闭,在出现问题时更容易定位错误源头并加以修复。 - **劣势** - 实现复杂度较高:为了使两个或更多个分离实体可以协作完成特定功能,则必须采用诸如管道、消息队列或者套接字等方式来进行必要的沟通协调工作[^2]。 - 效率较低:相比于简单的指针指向目标对象而言,这些间接的方法通常伴随着更大的延迟及更多的计算负担[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值