Day21

发布时间:2023年12月28日

Day21

一,线程的局部变量分享

1.1分享一个数据

public class Test01 {
	/**
	 * 知识点:线程局部变量共享
	 * 
	 * 注意:共享1个数据
	 */
	
	public static void main(String[] args) {
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				//要共享的数据
				int num = 10;
				
				//存数据
				DataSource.map.put(Thread.currentThread(), num);
				
				A a = new A();
				B b = new B();
				a.println();//10
				b.println();//10
			}
		}, "线程1").start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				//要共享的数据
				int num = 20;
				
				//存数据
				DataSource.map.put(Thread.currentThread(), num);
				
				A a = new A();
				B b = new B();
				a.println();//20
				b.println();//20
			}
		}, "线程2").start();
		
	}
}

创建数据源(集合)用于存储

import java.util.concurrent.ConcurrentHashMap;
//数据源
public class DataSource {

	public static final ConcurrentHashMap<Thread, Integer> map;
	
	static{
		map = new ConcurrentHashMap<>();
	}
}
public class A {
	public void println(){
		Thread thread = Thread.currentThread();
		Integer value = DataSource.map.get(thread);
		
		System.out.println(thread.getName() + "里的A类对象获取了数据:" + value);
	}
}
public class B {

	public void println(){
		Thread thread = Thread.currentThread();
		Integer value = DataSource.map.get(thread);
		
		System.out.println(thread.getName() + "里的B类对象获取了数据:" + value);
	}
}

1.2,分享多个数据

public class Test01 {
	/**
	 * 知识点:线程局部变量共享
	 * 
	 * 注意:共享多个数据
	 */
	
	public static void main(String[] args) {
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				//要共享的数据
				Data data = new Data("aaa", 10);
				
				//存数据
				DataSource.map.put(Thread.currentThread(), data);
				
				A a = new A();
				B b = new B();
				a.println();//10
				b.println();//10
			}
		}, "线程1").start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				//要共享的数据
				Data data = new Data("bbb", 20);
				
				//存数据
				DataSource.map.put(Thread.currentThread(), data);
				
				A a = new A();
				B b = new B();
				a.println();//20
				b.println();//20
			}
		}, "线程2").start();
		
	}
}
import java.util.concurrent.ConcurrentHashMap;

//数据源
public class DataSource {

	public static final ConcurrentHashMap<Thread, Data> map;
	
	static{
		map = new ConcurrentHashMap<>();
	}
}


public class B {

	public void println(){
		Thread thread = Thread.currentThread();
		Data value = DataSource.map.get(thread);
		
		System.out.println(thread.getName() + "里的B类对象获取了数据:" + value);
	}
}



public class A {

	public void println(){
		Thread thread = Thread.currentThread();
		Data value = DataSource.map.get(thread);
		
		System.out.println(thread.getName() + "里的A类对象获取了数据:" + value);
	}
}
//数据类
public class Data {

	private String str;
	private int num;
	
	public Data() {
	}

	public Data(String str, int num) {
		this.str = str;
		this.num = num;
	}

	public String getStr() {
		return str;
	}

	public void setStr(String str) {
		this.str = str;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	@Override
	public String toString() {
		return str + " -- " + num;
	}
}

1.3分享多个数据–ThreadLocal

public class Test01 {
	/**
	 * 知识点:线程局部变量共享
	 * 
	 * 注意:共享多个数据 -- ThreadLocal
	 */
	
	public static void main(String[] args) {
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				//要共享的数据
				Data data = Data.getInstance("aaa", 10);
				data = Data.getInstance("aaaaaa", 10000);
				
				//存数据
				DataSource.local.set(data);//把共享的数据存入ThreadLoad中(根据当前线程存储)
				
				A a = new A();
				B b = new B();
				a.println();//10
				b.println();//10
			}
		}, "线程1").start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				//要共享的数据
				Data data = Data.getInstance("bbb", 20);
				
				//存数据
				DataSource.local.set(data);//把共享的数据存入ThreadLoad中(根据当前线程存储)
				
				A a = new A();
				B b = new B();
				a.println();//20
				b.println();//20
			}
		}, "线程2").start();
		
	}
}
//数据源
public class DataSource {

	public static final ThreadLocal<Data> local;
	
	static{
		local = new ThreadLocal<>();
	}
}


public class B {

	public void println(){
		Thread thread = Thread.currentThread();
		Data value = DataSource.local.get();
		
		System.out.println(thread.getName() + "里的B类对象获取了数据:" + value);
	}
}


public class A {

	public void println(){
		Thread thread = Thread.currentThread();
		Data value = DataSource.local.get();//获取当前线程的ThreadLocal中共享数据
		
		System.out.println(thread.getName() + "里的A类对象获取了数据:" + value);
	}
}
//数据类
public class Data {

	private String str;
	private int num;
	
	private Data() {
	}

	private Data(String str, int num) {
		this.str = str;
		this.num = num;
	}
	
	public static Data getInstance(String str,int num){
		//获取当前线程共享的Data对象
		Data data = DataSource.local.get();
		
		if(data == null){//说明当前线程没有共享的data对象
			data = new Data(str, num);
			DataSource.local.set(data);
		}else{
			//当前线程有共享的data对象,就更新对象中的数据(属性)
			data.setStr(str);
			data.setNum(num);
		}
		
		return data;
	}

	public String getStr() {
		return str;
	}

	public void setStr(String str) {
		this.str = str;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	@Override
	public String toString() {
		return str + " -- " + num;
	}
}

二,线程安全

1,使用线程类的方式–同步代码块

需求:铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,请编写多线程程序来模拟这个效果
窗口001正在销售第1张票
窗口001正在销售第2张票
窗口002正在销售第3张票
。。。
窗口002正在销售第1000张票
窗口002票已经销售完毕
窗口001票已经销售完毕
窗口003票已经销售完毕

public class Test01 {
	/**
	 * 知识点:线程安全
		
		问题1:三个窗口各卖了1000张票,一共卖了3000张
		出现原因:三个线程调用3次run方法,allTicket和currentTicker就有3份
		解决方案:allTicket和currentTicker让三个线程共享
		
		问题2:有的票没有卖,有的票卖了重票
		出现原因:线程1抢到CPU资源后做了currentTicker++,正准备输出时退出CPU资源,其他线程抢到CPU资源后,又做了currentTicker++
		解决方案:currentTicker++和票的输出必须同时执行完毕后,其他线程才能再做currentTicker++
		
		问题3:currentTicker卖了1001和1002
		出现原因:多个线程都可以进入while判断
		解决方案:在锁中再次判断
		
		线程安全:线程之间产生互斥
		经验:多个线程想要互斥,就必须使用同一个锁对象!!!
		
		synchronized:
			同步代码块:
				synchronized(锁对象){//自动上锁
					...想要互斥的代码...
				}//自动解锁
			
			
		Lock:
	 */
	public static  void main(String[] args) {
		
		MyThread t1 = new MyThread("窗口001");
		MyThread t2 = new MyThread("窗口002");
		MyThread t3 = new MyThread("窗口003");
		
		t1.start();
		t2.start();
		t3.start();
	}
}
public class MyThread extends Thread{
	
	private static int allTicket = 1000;
	private static int currentTicket = 0;
	private static Object obj = new Object();
	
	public MyThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		
		while(currentTicket < allTicket){
//			synchronized("abc"){
//			synchronized(Integer.class){
			synchronized(obj){
				if(currentTicket < allTicket){
					currentTicket++;
					System.out.println(Thread.currentThread().getName() + "正在销售第" + currentTicket + "张票");
				}
				if(currentTicket == allTicket){
					System.out.println(Thread.currentThread().getName() +  "票已卖完");
				}
			}
		}
	}
}

2,使用线程类的方式–同步方法


public class Test01 {
	/**
	 * 知识点:线程安全
	 * 
		
		问题1:三个窗口各卖了1000张票,一共卖了3000张
		出现原因:三个线程调用3次run方法,allTicket和currentTicker就有3份
		解决方案:allTicket和currentTicker让三个线程共享
		
		问题2:有的票没有卖,有的票卖了重票
		出现原因:线程1抢到CPU资源后做了currentTicker++,正准备输出时退出CPU资源,其他线程抢到CPU资源后,又做了currentTicker++
		解决方案:currentTicker++和票的输出必须同时执行完毕后,其他线程才能再做currentTicker++
		
		问题3:currentTicker卖了1001和1002
		出现原因:多个线程都可以进入while判断
		解决方案:在锁中再次判断
		
		线程安全:线程之间产生互斥
		经验:多个线程想要互斥,就必须使用同一个锁对象!!!
		
		synchronized:
			同步代码块:
				synchronized(锁对象){//自动上锁
					...想要互斥的代码...
				}//自动解锁
			
			同步方法:
				//成员同步方法 -- 锁对象:this
				public synchronized void method(){//自动上锁
					...想要互斥的代码...
				}//自动解锁
				
				//静态同步方法 -- 锁对象:该类的class对象
				public static synchronized void method(){//自动上锁
					...想要互斥的代码...
				}//自动解锁
			
		Lock:
	 */
	public static  void main(String[] args) {
		
		MyThread t1 = new MyThread("窗口001");
		MyThread t2 = new MyThread("窗口002");
		MyThread t3 = new MyThread("窗口003");
		
		t1.start();
		t2.start();
		t3.start();
	}
}
public class MyThread extends Thread{
	
	private static int allTicket = 1000;
	private static int currentTicket = 0;
	
	public MyThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		
		while(currentTicket < allTicket){
			method();
		}
	}
	
	//锁对象:MyThread.class
	public static synchronized void method(){
		if(currentTicket < allTicket){
			currentTicket++;
			System.out.println(Thread.currentThread().getName() + "正在销售第" + currentTicket + "张票");
		}
		if(currentTicket == allTicket){
			System.out.println(Thread.currentThread().getName() +  "票已卖完");
		}
	}
}

3,使用线程类的方式–Lock()锁

public class Test01 {
	/**
	 * 知识点:线程安全
	 * 
		
		问题1:三个窗口各卖了1000张票,一共卖了3000张
		出现原因:三个线程调用3次run方法,allTicket和currentTicker就有3份
		解决方案:allTicket和currentTicker让三个线程共享
		
		问题2:有的票没有卖,有的票卖了重票
		出现原因:线程1抢到CPU资源后做了currentTicker++,正准备输出时退出CPU资源,其他线程抢到CPU资源后,又做了currentTicker++
		解决方案:currentTicker++和票的输出必须同时执行完毕后,其他线程才能再做currentTicker++
		
		问题3:currentTicker卖了1001和1002
		出现原因:多个线程都可以进入while判断
		解决方案:在锁中再次判断
		
		线程安全:线程之间产生互斥
		经验:多个线程想要互斥,就必须使用同一个锁对象!!!
		
		synchronized:
			同步代码块:
				synchronized(锁对象){//自动上锁
					...想要互斥的代码...
				}//自动解锁
			
			同步方法:
				//成员同步方法 -- 锁对象:this
				public synchronized void method(){//自动上锁
					...想要互斥的代码...
				}//自动解锁
				
				//静态同步方法 -- 锁对象:该类的class对象
				public static synchronized void method(){//自动上锁
					...想要互斥的代码...
				}//自动解锁
			
		Lock:
			//锁对象
			Lock lock = new ReentrantLock();
			lock.lock();//手动上锁
			...想要互斥的代码...
			lock.unlock();//手动解锁
			
	 */
	public static  void main(String[] args) {
		
		MyThread t1 = new MyThread("窗口001");
		MyThread t2 = new MyThread("窗口002");
		MyThread t3 = new MyThread("窗口003");
		
		t1.start();
		t2.start();
		t3.start();
	}
}

4,使用任务类的方式解决–同步代码块

  需求:铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,请编写多线程程序来模拟这个效果
		窗口001正在销售第1张票
		窗口001正在销售第2张票
		窗口002正在销售第3张票
		。。。
		窗口002正在销售第1000张票
		窗口002票已经销售完毕
		窗口001票已经销售完毕
		窗口003票已经销售完毕
public class Test01 {
	/**
	 * /**
	 * 知识点:线程安全
	 * 
	
		
		问题1:三个窗口各卖了1000张票,一共卖了3000张
		出现原因:三个线程调用3次run方法,allTicket和currentTicker就有3份
		解决方案:让三个线程操作同一个任务
		
		问题2:有的票没有卖,有的票卖了重票
		出现原因:线程1抢到CPU资源后做了currentTicker++,正准备输出时退出CPU资源,其他线程抢到CPU资源后,又做了currentTicker++
		解决方案:currentTicker++和票的输出必须同时执行完毕后,其他线程才能再做currentTicker++
		
		问题3:currentTicker卖了1001和1002
		出现原因:多个线程都可以进入while判断
		解决方案:在锁中再次判断
		
		线程安全:线程之间产生互斥
		经验:多个线程想要互斥,就必须使用同一个锁对象!!!
		
	 */
	public static void main(String[] args) {
		
		Task task = new Task();
		
		Thread t1 = new Thread(task, "窗口001");
		Thread t2 = new Thread(task, "窗口002");
		Thread t3 = new Thread(task, "窗口003");
		
		t1.start();
		t2.start();
		t3.start();
	}
}
public class Task implements Runnable{

	private int allTicket = 1000;
	private int currentTicket = 0;
	private static Object obj1 = new Object();
	private Object obj2 = new Object();
	
	@Override
	public void run() {
		
		while(currentTicket < allTicket){
			//synchronized("abc"){
			//synchronized(Integer.class){
			//synchronized(obj1){
			//synchronized(obj2){
			synchronized(this){
				if(currentTicket < allTicket){
					currentTicket++;
					System.out.println(Thread.currentThread().getName() + "正在销售第" + currentTicket + "张票");
				}
				if(currentTicket == allTicket){
					System.out.println(Thread.currentThread().getName() + "票已售完");
				}
			}
		}
	}
}

5,使用任务类的方式解决–同步方法

public class Test01 {
	/**
	 * /**
	 * 知识点:线程安全
	 * 
		
		问题1:三个窗口各卖了1000张票,一共卖了3000张
		出现原因:三个线程调用3次run方法,allTicket和currentTicker就有3份
		解决方案:让三个线程操作同一个任务
		
		问题2:有的票没有卖,有的票卖了重票
		出现原因:线程1抢到CPU资源后做了currentTicker++,正准备输出时退出CPU资源,其他线程抢到CPU资源后,又做了currentTicker++
		解决方案:currentTicker++和票的输出必须同时执行完毕后,其他线程才能再做currentTicker++
		
		问题3:currentTicker卖了1001和1002
		出现原因:多个线程都可以进入while判断
		解决方案:在锁中再次判断
		
		线程安全:线程之间产生互斥
		经验:多个线程想要互斥,就必须使用同一个锁对象!!!
		
	 */
	public static void main(String[] args) {
		
		Task task = new Task();
		
		Thread t1 = new Thread(task, "窗口001");
		Thread t2 = new Thread(task, "窗口002");
		Thread t3 = new Thread(task, "窗口003");
		
		t1.start();
		t2.start();
		t3.start();
	}
}
public class Task implements Runnable{

	private int allTicket = 1000;
	private int currentTicket = 0;
	
	@Override
	public void run() {
		
		while(currentTicket < allTicket){
			method();
		}
	}
	
	public synchronized void method(){
		if(currentTicket < allTicket){
			currentTicket++;
			System.out.println(Thread.currentThread().getName() + "正在销售第" + currentTicket + "张票");
		}
		if(currentTicket == allTicket){
			System.out.println(Thread.currentThread().getName() + "票已售完");
		}
	}
}

6,使用任务类的方式解决–Lock()锁

public class Test01 {
	/**
	 * /**
	 * 知识点:线程安全
	 * 
		
		问题1:三个窗口各卖了1000张票,一共卖了3000张
		出现原因:三个线程调用3次run方法,allTicket和currentTicker就有3份
		解决方案:让三个线程操作同一个任务
		
		问题2:有的票没有卖,有的票卖了重票
		出现原因:线程1抢到CPU资源后做了currentTicker++,正准备输出时退出CPU资源,其他线程抢到CPU资源后,又做了currentTicker++
		解决方案:currentTicker++和票的输出必须同时执行完毕后,其他线程才能再做currentTicker++
		
		问题3:currentTicker卖了1001和1002
		出现原因:多个线程都可以进入while判断
		解决方案:在锁中再次判断
		
		线程安全:线程之间产生互斥
		经验:多个线程想要互斥,就必须使用同一个锁对象!!!
		
	 */
	public static void main(String[] args) {
		
		Task task = new Task();
		
		Thread t1 = new Thread(task, "窗口001");
		Thread t2 = new Thread(task, "窗口002");
		Thread t3 = new Thread(task, "窗口003");
		
		t1.start();
		t2.start();
		t3.start();
	}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Task implements Runnable{

	private int allTicket = 1000;
	private int currentTicket = 0;
	private Lock lock = new ReentrantLock();
	
	@Override
	public void run() {
		
		while(currentTicket < allTicket){
			lock.lock();
			if(currentTicket < allTicket){
				currentTicket++;
				System.out.println(Thread.currentThread().getName() + "正在销售第" + currentTicket + "张票");
			}
			if(currentTicket == allTicket){
				System.out.println(Thread.currentThread().getName() + "票已售完");
			}
			lock.unlock();
		}
	}
}

三,Work–计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果

1,使用线程类去解决该需求

public class Test01 {
	public static void main(String[] args) throws InterruptedException {
		
		//创建数组
		int[] arr = new int[20000];
		
		//初始化数组中的元素
		for (int i = 0; i < arr.length; i++) {
			arr[i] = i+1;
		}
		
		//创建子线程
		MyThread t1 = new MyThread(arr, 0, 5000);
		MyThread t2 = new MyThread(arr, 5000, 10000);
		MyThread t3 = new MyThread(arr, 10000, 15000);
		MyThread t4 = new MyThread(arr, 15000, 20000);
		
		//启动线程
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
		//问题出现的原因:让四个子线程全部执行完毕,才能执行主线程
		//解决思路:让主线程阻塞
		
		//解决方案1:休眠
		//Thread.sleep(1);
		
		//解决方案2:
		//while(t1.isFlag() || t2.isFlag() || t3.isFlag() || t4.isFlag()){}
		
		//解决方案3:
		t1.join();
		t2.join();
		t3.join();
		t4.join();
		
		//汇总结果
		System.out.println(t1.getSum() + t2.getSum() + t3.getSum() + t4.getSum());
	}
}
public class MyThread extends Thread{
	
	private int[] arr;
	private int startIndex;
	private int endIndex;
	
	public MyThread(int[] arr, int startIndex, int endIndex) {
		this.arr = arr;
		this.startIndex = startIndex;
		this.endIndex = endIndex;
	}
	
	private int sum;
	private boolean flag = true;
	
	@Override
	public void run() {
		
		for (int i = startIndex; i <endIndex; i++) {
			sum += arr[i];
		}
		flag = false;
	}

	public int getSum() {
		return sum;
	}

	public boolean isFlag() {
		return flag;
	}
}

2,使用任务类去解决

public class Test01 {
	public static void main(String[] args) throws InterruptedException {

		//创建数组
		int[] arr = new int[20000];

		//初始化数组中的元素
		for (int i = 0; i < arr.length; i++) {
			arr[i] = i+1;
		}

		//创建任务对象 
		Task task1 = new Task(arr, 0, 5000);
		Task task2 = new Task(arr, 5000, 10000);
		Task task3 = new Task(arr, 10000, 15000);
		Task task4 = new Task(arr, 15000, 20000);

		//创建线程对象
		Thread t1 = new Thread(task1);
		Thread t2 = new Thread(task2);
		Thread t3 = new Thread(task3);
		Thread t4 = new Thread(task4);

		//启动线程
		t1.start();
		t2.start();
		t3.start();
		t4.start();

		//问题出现的原因:让四个子线程全部执行完毕,才能执行主线程
		//解决思路:让主线程阻塞

		//解决方案1:休眠
		//Thread.sleep(1);

		//解决方案2:
		//while(task1.isFlag() || task2.isFlag() || task3.isFlag() || task4.isFlag()){}

		//解决方案3:
		t1.join();
		t2.join();
		t3.join();
		t4.join();

		//汇总结果
		System.out.println(task1.getSum() + task2.getSum() + task3.getSum() + task4.getSum());
	}
}
public class Task implements Runnable{

	private int[] arr;
	private int startIndex;
	private int endIndex;
	
	public Task(int[] arr, int startIndex, int endIndex) {
		this.arr = arr;
		this.startIndex = startIndex;
		this.endIndex = endIndex;
	}
	
	private int sum;
	private boolean flag = true;
	
	public int getSum() {
		return sum;
	}

	@Override
	public void run() {
		
		for (int i = startIndex; i <endIndex; i++) {
			sum += arr[i];
		}
		flag = false;
	}

	public boolean isFlag() {
		return flag;
	}
}
文章来源:https://blog.csdn.net/haikeydnk/article/details/135255255
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。