2024年大数据最全Java面向对象程序开发——多线程开发(4),2024年最新2024年您应该知道的技术之一

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

@Override
public String call() throws Exception {
	System.out.println("Demo3开始运行");
	Thread.sleep(3000);  //暂停3000毫秒
	System.out.println("Demo3运行结束");
	return "二哈喇子";
}

}


测试类:



public class 实现Callable接口线程测试 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Demo3 d3 = new Demo3();
//创建FutureTask类对象 获得线程执行后返回值
FutureTask ft = new FutureTask<>(d3);
//创建Thread类对象
Thread thread = new Thread(ft);

	thread.start();
	String result = ft.get();
	
	System.out.println("Demo3执行完的结果是"+result);
	System.out.println("main执行结束");
}

}


### Runnable接口和继承Thread类的区别


这个问题面试的时候经常问


① 、创建线程的方式不同


② 、设置线程名方式不同


③、获取线程名方式不同


④ 、由于Java是单继承,一个类继承Thread类以后不能继承其他类,扩展性不好。而实现Runnable接口则可以侧面实现了多继承


⑤、继承Thread类不能实现线程变量资源共享,注意,是线程里的变量实现Runnable 接口线程变量是可以共享的,也可以不共享,看创建线程的方式


## 多线程安全怎么处理


**互斥访问:** 多个线程同时访问同一个共享资源时,需要保证同一时刻只有一个线程能够访问该资源,以避免数据竞争的发生。可以使用synchronized关键字、Lock接口等机制来实现互斥访问。


**原子操作:** 原子操作是指一系列不可分割的操作,不会被其他线程中断。在多线程环境下,需要保证原子操作的执行,以避免数据的不一致性。可以使用AtomicInteger、AtomicLong等原子类来实现原子操作。


**可见性:** 多个线程同时访问同一个变量时,需要保证对该变量的读写操作对其他线程是可见的,以避免出现数据不一致的情况。可以使用volatile关键字来保证变量的可见性。


## 线程同步机制


模拟电影院卖100张票



public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);//线程1
Thread t2 = new Thread(myThread);//线程2
t1.start();
t2.start();
}
}
class MyThread implements Runnable{
private int num =100;//定义一个共享票源
@Override
public void run() {
while(num > 0) {//还有票
try {
Thread.sleep(50);//为了模拟买票操作耗时
System.out.println(Thread.currentThread().getName()+“正在卖”+num+“票”);//获取当前线程名
num–;
} catch (InterruptedException e) {
e.printStackTrace();
}

	}
}

}


线程安全问题是由全局变量及静态变量引起的,若多线程同时执行写操作(单纯读操作一般是线程安全的),线程会去抢夺cpu资源完成操作,造成线程不安全。


同步机制:  
 1、volatile  
 2、同步锁  
 3、同步方法  
 4、CAS  
 5、Lock锁



synchronized(同步锁){
需要同步操作的代码:1锁对象可以是任意类型。2多个线程对象要使用同一把锁。
}

public synchronized void method(){
可能会产生线程安全问题的代码
}

class Ticket implements Runnable{
Lock lock = new ReentrantLock();
private int num = 100;//定一个多线程共享的票源
@Override
public void run() {
while (true){
//上锁
lock.lock();
if (num>0){
…//代码省略
}
//释放锁
lock.unlock();
}
}
}


### volatile


假如说线程1修改了data变量的值为1,然后将这个修改写入自己的本地工作内存。  
 那么此时,线程1的工作内存里的data值为1。  
 然而,主内存里的data值还是为0!线程2的工作内存里的data值还是0啊?!


作用:


1、一旦data变量定义的时候前面加了volatile来修饰的话,那么线程1只要修改data变量的值,就会在修改完自己本地工作内存的data变量值之后,强制将这个data变量最新的值刷回主内存,必须让主内存里的data变量值立马变成最新的值!  
 2、如果此时别的线程的工作内存中有这个data变量的本地缓存,也就是一个变量副本的话,那么会强制让其他线程的工作内存中的data变量缓存直接失效过期,不允许再次读取和使用了!  
 3、如果线程2在代码运行过程中再次需要读取data变量的值,他就必须重新从主内存中加载data变量最新的值!那么不就可以读取到data = 1这个最新的值了!


#### 同步锁


![在这里插入图片描述](https://img-blog.csdnimg.cn/76f265e191e74e26b20a53f52697dc96.png)



public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);//线程1
Thread t2 = new Thread(myThread);//线程2
t1.start();
t2.start();
}
}
class MyThread implements Runnable{
private int num =100;//定义一个共享票源
Object obj = new Object();
@Override
public void run() {
while(true) {//窗口永远开启
synchronized(obj) {//同步锁
if(num > 0) {
try {
Thread.sleep(50);//为了模拟买票操作耗时
System.out.println(Thread.currentThread().getName()+“正在卖”+num+“票”);//获取当前线程名
num–;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}


### 同步方法



public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);//线程1
Thread t2 = new Thread(myThread);//线程2
t1.start();
t2.start();
}
}
class MyThread implements Runnable{
private int num =100;//定义一个共享票源
Object obj = new Object();
@Override
public void run() {
while(true) {//窗口永远开启
method();
}
}
public synchronized void method(){ //同步方法
if(num > 0) {
try {
Thread.sleep(50);//为了模拟买票操作耗时
System.out.println(Thread.currentThread().getName()+“正在卖”+num+“票”);//获取当前线程名
num–;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


 CAS(Compare and Set)


### 同步和异步有什么区别


同步(Synchronous):在同步处理中,一个任务的完成需要等待另一个任务完成后才能进行。适用于需要按照一定顺序执行任务的情况,例如多个线程共享数据、调用需要花费长时间才能完成的方法等


异步(Asynchronous):在异步处理中,多个任务可以同时进行,不必等待前一个任务完成。适用于不需要等待前一个任务完成就可以执行下一个任务的情况,例如发送一个请求并希望在得到响应后继续执行其他任务。


### lock锁


使用ReentrantLock实现同步, lock()方法上锁,unlock()方法释放锁



import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);//线程1
Thread t2 = new Thread(myThread);//线程2
t1.start();
t2.start();
}
}
class MyThread implements Runnable{
private int num =100;//定义一个共享票源
Lock lock = new ReentrantLock(); //声明一个lock对象
@Override
public void run() {
while(true) {//还有票
lock.lock(); //上锁
if(num > 0) {
try {
Thread.sleep(50);//为了模拟买票操作耗时
System.out.println(Thread.currentThread().getName()+“正在卖”+num+“票”);//获取当前线程名
num–;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock(); //释放锁
}
}
}


## 线程池


**问题**:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。


**线程池**:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。


**好处**:


1、降低资源消耗,如果线程池无空闲,则需等待其他任务执行完毕后归还线程。


2、提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。


3、提高线程的可管理性,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。



import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*1.创建线程池对象
2.实现Runnable接口子类
3.使用线程池
4.关闭线程池*/
public class Test {
public static void main(String[] args) {
//1.创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(2); //包含2个线程对象
MyThread m = new MyThread(); //2.实现Runnable接口子类
// Thread t = new Thread(m);
// t.start();
service.submit(m);//3.使用线程池
service.submit(m);//submit执行之后程序并没有关闭,是因为线程池控制了线程的关闭
service.submit(m);
// service.shutdown();//4.关闭线程池
// service.submit(m); //关闭之后再执行则报异常
}
}
class MyThread implements Runnable{

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

s MyThread implements Runnable{

[外链图片转存中…(img-Qn9nVfJX-1714863079092)]
[外链图片转存中…(img-uc3Eot8I-1714863079092)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 49
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值