Day21
2023-12-27 23:27:16
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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!