多线程共享数据

线程范围的共享数据包括线程范围内共享和线程间共享数据

  • 线程范围内共享数据
线程范围内共享数据有两种方式:自定义一个Map<Thread, Object>用来保存线程的数据或者是用ThreadLocal类。
使用Map<Thread, Object>
package traditional;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadScopeShareData {

	private static Map<Thread,Integer> threadMap = new HashMap<Thread,Integer>();
	public static void main(String[] args) {
		
		for(int i = 0 ; i < 2; i++){//开启两个线程
			new Thread(new Runnable(){
				@Override
				public void run() {
					int data = new Random().nextInt();
					System.out.println(Thread.currentThread().getName()+" has put data : "+data);
					threadMap.put(Thread.currentThread(), data);
					new A().get();
					new B().get();
				}
			}).start();
		}
	}
	
	static class A{
		public void get(){
			int data = threadMap.get(Thread.currentThread());
			System.out.println("A from "+ Thread.currentThread().getName()+
					"has put data : "+ data);
		}
	}
	
	static class B{
		public void get(){
			int data = threadMap.get(Thread.currentThread());
			System.out.println("B from "+ Thread.currentThread().getName()+
					"has put data : "+ data);
		}
	}
}

使用ThreadLocal类
package traditional;

import java.util.Random;

/**
 * ThreadLocal实现线程范围的共享变量
 */
public class ThreadLocalTest {

	private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();

	
	// private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();//不要这样做
	public static void main(String[] args) {

		for (int i = 0; i < 2; i++) {// 开启两个线程
			new Thread(new Runnable() {
				@Override
				public void run() {
					int data = new Random().nextInt();
					System.out.println(Thread.currentThread().getName() + " has put data : " + data);
					threadLocal.set(data);// 把data数据存储到当前线程

					/*
					 * MyThreadScopeData myData = new MyThreadScopeData();
					 * myData.setName("name"+data); myData.setAge(data);
					 * myThreadScopeData.set(myData);
					 */

					MyThreadScopeData.getThreadInstance().setName("name" + data);
					MyThreadScopeData.getThreadInstance().setAge(data);

					new A().get();
					new B().get();
				}
			}).start();
		}
	}

	static class A {
		public void get() {
			int data = threadLocal.get();// 取到当前线程的data值
			System.out.println("A from " + Thread.currentThread().getName() + " has put data : " + data);

			MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
			System.out.println("A from " + Thread.currentThread().getName() + " get myData : " + myData.getName() + ", "
					+ myData.getAge());
		}
	}

	static class B {
		public void get() {
			int data = threadLocal.get();// 取到当前线程的data值
			System.out.println("B from " + Thread.currentThread().getName() + " has put data : " + data);
			MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
			System.out.println("B from " + Thread.currentThread().getName() + " get myData : " + myData.getName() + ", "
					+ myData.getAge());
		}
	}
}

/**
 * 把ThreadLocal放到封装的类中
 * 
 * 专门与线程绑定 在线程的任何地方调用该类的instance,就会产生与当前线程有关的实例
 *
 */
class MyThreadScopeData {
	// 类似于单例设计模式
	private MyThreadScopeData() {
	}

	public /* synchronized */ static MyThreadScopeData getThreadInstance() {
		MyThreadScopeData instance = map.get();
		if (instance == null) {
			instance = new MyThreadScopeData();
			map.set(instance);
		}
		return instance;
	}

	// private static MyThreadScopeData instance = null;
	private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();

	private String name;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}
  • 线程之间共享数据
1、如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如买票系统就可以这么做。
2、如果每个线程执行的代码不相同,这时候就需要用不同的Runnable对象
2.1、把共享变量封装在一个对象中,然后把这个对象逐一传递给各个Runnable对象。(可以写自己的Runnable,然后以构造函数的方式传递共享变量进去)
// 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
package traditional;
 
public class MultiThreadShareData {
 
  
   public static void main(String[] args) {
     
      final ShareData1 data1 = new ShareData1();
      new Thread(new Runnable(){
         @Override
         public void run() {
            data1.decrement();
         }
      }).start();
     
      new Thread(new Runnable(){
         @Override
         public void run() {
            data1.increment();
         }
      }).start();
   }
  
}
class ShareData1{
  
   private int j = 0;
   public synchronized void increment(){
      j++;
   }
  
   public synchronized void decrement(){
      j--;
   }
  
}
 
内部类可以访问外部类的成员变量
另外的方法:

package traditional;
 
public class ThreadTest1 {
   private int j;
 
   public static void main(String args[]) {
      ThreadTest1 tt = new ThreadTest1();
      Inc inc = tt.new Inc();
      Dec dec = tt.new Dec();
      for (int i = 0; i < 2; i++) {
         Thread t = new Thread(inc);
         t.start();
         t = new Thread(dec);
         t.start();
      }
   }
 
   private synchronized void inc() {
      j++;
      System.out.println(Thread.currentThread().getName() + "-inc:" + j);
   }
 
   private synchronized void dec() {
      j--;
      System.out.println(Thread.currentThread().getName() + "-dec:" + j);
   }
 
   class Inc implements Runnable {
      public void run() {
         for (int i = 0; i < 100; i++) {
            inc();
         }
      }
   }
 
   class Dec implements Runnable {
      public void run() {
         for (int i = 0; i < 100; i++) {
            dec();
         }
      }
   }



<think>好的,用户的问题是关于Python多线程环境下如何实现数据共享。我需要先回顾一下相关知识,确保回答准确。 首先,Python的多线程因为GIL的存在,同一时间只能有一个线程执行字节码,这对CPU密集型任务有限制,但IO密集型任务还是可以受益。用户提到数据共享,所以需要说明线程之间如何共享数据,以及可能的同步机制。 根据引用[2],多线程中每个线程有自己的内存空间,不能直接共享内存,但进程的资源是共享的。所以实际上,线程可以访问同一进程的全局变量。不过,这可能导致竞争条件,需要锁机制来保护数据。 然后,引用[3]提到线程共享进程的内存空间,所以全局变量和数据结构是共享的。但需要线程安全的方式操作它们,比如使用Lock、RLock、Event等同步原语。 用户可能想知道具体有哪些方法,比如使用队列、共享内存结构,或者第三方库。需要列举常见的几种方式,并举例说明,比如使用threading.Lock()来保护共享变量,或者使用Queue模块的队列进行线程间通信。 还要注意,虽然线程可以共享数据,但不当的同步会导致死锁或数据不一致。因此,需要强调正确使用锁的重要性,以及何时该使用其他结构如Condition或Semaphore。 可能用户对多线程和多进程的数据共享方式有混淆,需要区分。根据引用[2],多线程通过全局变量等共享,而多进程需要其他机制如共享内存。但问题明确是多线程,所以重点放在线程共享方法上。 需要检查是否有遗漏的实现方式,比如使用线程安全的容器如queue.Queue,或者使用Value和Array从multiprocessing模块,但要注意这些可能更常用于多进程,不过multiprocessing模块有些结构也可以在多线程中使用,但需确认。 最后,根据用户提供的引用,引用[1]提到文件锁,但用户的问题更广泛,涉及一般数据共享,所以可能需要提到文件锁仅在涉及文件IO时使用,而内存中的数据共享使用其他方法。 总结回答的结构:先说明线程共享内存的特性,然后列出几种实现方式,如全局变量加锁、使用队列、使用线程安全的数据结构,并给出示例代码。同时提醒注意事项,比如GIL的影响和同步的重要性。 需要确保示例代码正确,比如正确使用with语句管理锁,避免死锁。另外,引用相关文献,如引用[2]和[3]来支持线程共享内存的观点,引用[1]可能仅在文件操作时相关。 可能用户的实际应用场景是数据处理或并发IO操作,所以例子应贴近这些情况,比如计数器、任务队列等。 现在组织内容,分点回答,确保清晰易懂,符合用户要求的结构。</think>在Python多线程环境下,由于线程共享进程的内存空间,数据共享主要通过以下方式实现: ### 一、全局变量共享 所有线程默认共享全局变量,但需通过锁机制保证线程安全: ```python import threading counter = 0 lock = threading.Lock() def increment(): global counter with lock: counter += 1 threads = [] for _ in range(10): t = threading.Thread(target=increment) threads.append(t) t.start() for t in threads: t.join() print(counter) # 输出10 ``` 此方式适合简单计数场景,需注意$lock.acquire()$和$lock.release()$的成对使用[^2]。 ### 二、队列(Queue)通信 使用线程安全的`queue.Queue`实现生产者-消费者模式: ```python from queue import Queue import threading data_queue = Queue() def producer(): for i in range(5): data_queue.put(i) def consumer(): while True: item = data_queue.get() print(f"Processed: {item}") data_queue.task_done() t1 = threading.Thread(target=producer) t2 = threading.Thread(target=consumer) t1.start(); t2.start() t1.join(); data_queue.join() ``` 队列内部已实现锁机制,适合任务分发场景[^3]。 ### 三、共享内存结构 使用`threading.local()`创建线程局部数据: ```python shared_data = threading.local() def show_data(): print(shared_data.value) def worker(value): shared_data.value = value show_data() threads = [threading.Thread(target=worker, args=(i,)) for i in range(3)] for t in threads: t.start() for t in threads: t.join() ``` 该方式实现线程隔离的共享数据,每个线程独立操作自己的数据副本。 ### 四、高级同步机制 1. **事件(Event)**:通过`threading.Event()`实现线程间状态通知 2. **条件变量(Condition)**:使用`threading.Condition()`实现复杂同步逻辑 3. **信号量(Semaphore)**:通过`threading.Semaphore(n)`控制并发访问数量 ### 注意事项 1. GIL导致多线程不适合CPU密集型任务,建议改用多进程[^2] 2. 文件操作时需额外加文件锁(如`fcntl`模块)[^1] 3. 优先使用`with lock`语句避免死锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值