1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Java中多线程 多线程的实现方式 同步代码块的方式

Java中多线程 多线程的实现方式 同步代码块的方式

时间:2020-09-24 11:14:39

相关推荐

Java中多线程 多线程的实现方式 同步代码块的方式

多线程

进程线程概念目前的程序是单线程线程的组成部分代码实现多线程的方式第一种方式第二种方式第三种方式 -- 线程池第四种方式:Callable 线程状态线程同步临界资源原子操作线程同步线程同步第一种方式:同步代码块线程同步第二种方式:同步方法线程同步第三种方式:Lock 死锁

进程

进程的概念

操作系统(OS)中正在执行的应用程序,目前操作系统允许多个进程同时工作,被称为多进程多进程并发执行原理

宏观上并行(一起执行);微观上串行(一个一个的执行),哪一个进程获取CPU时间片该进程获取执行权

线程

概念

在进程中,可以同时执行多个任务,每一个任务可以说是为一个线程,线程是进程的工作单位

线程也被称为轻量级的进程

目前的程序是单线程

以main函数的开始为开始,以main 函数的结束为结束,这个线程被称为主线程(Java中只有能代码实现多线程)

线程的组成部分

(1) cup

获取cpu时间片

(2) 数据

栈空间独立,堆空间共享每一个线程都有自己的独有栈空间;所有线程共享同一堆空间

(3) 程序代码

利用Java代码实现多线程

代码实现多线程的方式

第一种方式
类继承java.lang.Thread类,同时覆盖run()方法

注意:线程任务定义在run方法中创建线程对象

MyThread t = new MyThread();

开启线程

利用 start开启线程,jvm执行线程时会自动的 调用run方法

t.start();

第二种方式
类实现java.lang.Runnable接口,实现接口中run()方法

注意:实现run时,访问修饰符必须是public,任务代码定义在run方法中,当前类代表是任务类创建目标对象

MyTarget tg = new MyTarget();

创建线程对象,同时将目标对象作为参数进行传递

Thread t = new Thread(tg);

开启线程:调用start方法

t.start();

第三种方式 – 线程池

线程池

线程容器,将预先创建的线程对象存入到线程池中,只要将任务提交给线程池,会分配对象线程对象完成提交任务,线程池中的线程对象可以被重复使用

好处

避免频繁的创建线程和销毁,从而提高空间利用和执行效率

线程池常用的接口和类,位于java.util.concurrent包中

3.1Executor:线程池的顶级接口

3.2ExecutorService:是Executor的子接口,线程池的核心接口

submit(Runnable task):将线程任务提交给线程池

submit(Callable<\T> task):将线程任务提交给线程池shutdown(): 关闭线程池,将线程池的线程对象全部销毁

3.3Executors:获取线程池对象的工具类,其中方法基本都为静态方法

static ExecutorService newFixedThreadPool(int n):获取一 个固定数量线程的线程池,参数指定线程池中线程对象的数量static ExecutorService newCachedThreadPool():获取动 态数量线程对象的线程池,根据提交的任务需求,不够用时, 则自动完成线程创建

第四种方式:Callable
Callable接口

位于java.util.concurrent包中,类似于Runnable接口的应用,对应的对象代表线程任务

注意: Callable是泛型接口,泛型约束了接口中方法的返回值的数据类型接口中的方法

V call():带有返回值的方法,同时可以抛出 异常

Future< T> f= pool.submit(c1);Future是存储submit提交任务执行之后的结果

利用 Future中的get方法获取执行的结果

线程状态

初始状态

线程已被创建但尚未执行(start() 尚未被调用)可执行状态

线程可以执行,虽然不一定正在执行。CPU 时间随时可能被分配给该线程,从而使得它执行死亡状态

正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果,但是不被推荐,前者会产生异常,后者是强制终止,不会释放锁阻塞状态

线程不会被分配 CPU 时间,无法执行

static void sleep(long ms):如果在某一个线程中调用 Thread.sleep方法,则此线程进入有限期等待状态(计时状态/休眠,单位ms), 同时释放cpu;但是不释放该线程拥有得到锁标记

public final join():允许其他线程加入到当前线程中(调用join方法语句所在的线程),让调用join方法的线程先执行,等待其他线程任务执行结束之后,再执行自身的任务

线程同步

临界资源

被多个线程共享的同一个对象,此对象被称为临 界资源

原子操作

不可分割的多步操作,被视为一个整体,其执行顺序和步骤不能被打破

线程同步

多线程并发时,为了保证临界资源的正确性,而不能破坏程序中的原子操作(线程同步目的就是为保证原子操作的整体性,从而达到临界资源最终数据的正确性)

线程同步第一种方式:同步代码块

同步代码块对临界资源对象加锁

synchronized( 临界资源对象){// 原子操作}

定义位置

同步代码块定义在方法内部执行的原理

线程执行过程中,遇到同步代码块,只有线 程获取临界资源对象锁标记时,才能执行同步代码块{}中的 内容,并且只有{}中内容全部执行完成,才能释放该线程拥 有的锁标记;如果临界资源对象的锁标记被其他线程占用, 该线程进入阻塞状态(Blocked状态-等着需要的锁标记释放, 去获取),直到拿到所需要的锁标记才从阻塞状态结束,同时 再获取到cpu资源,才能继续执行同步代码块{}中内容

注意:线程同步时,不同的线程必须是抢占同一个对象锁 标记,才能达到线程同步的目的(原子操作不被破坏,临界资 源的正确性)

线程同步第二种方式:同步方法

修饰符 synchronized 返回值 方法名(形参列表){// 原子操作}

synchronized修饰方法被称为同步方法

0 同步方法等价于同步代码块

修饰符 返回值类型 方法名(形参列表){synchronized(this){// 方法中语句(包含原子操作)}}

线程同步第三种方式:Lock

Lock

接口,位于java.util.concurrent.locks包中,代表Lock中常用方法void lock():获取锁,如果被占用,则需要等待void unlock():释放锁 实现类

ReentrantLock

死锁

死锁现象:两个线程或是多个线程相互占用对方所需要的的 资源,而都不释放,导致彼此之间相互等待对方释放资源, 从而产生无限制的等待现象。结果:出现死锁后,不会抛出异常,也没有任何提示,只是所有的线程都处于阻塞状态,如果没有外力介入,程序将无 法继续解决方案 尽可能的调整加锁的方案尽量避免同步的嵌套嵌套可以采用线程间的通信,等待-通知

在Object类中有wait(等待)-notify/notifyAll(通知)方法wait():等待 让当前进入等待状态,释放cpu的同时,释放拥有的锁标记wait方法调用必须使用在调用它的对象所在的同步代码块中

synchronized(o){o.wait();}

notify:通知notify():通知一个线程从等待状态结束

notifyAll():通知所有的线程从等待状态结束notify/notifyAll方法的调用必须在调用它的对象所在同步代码块中

synchronized(o){o.notify();}

notify和notifyAll只是起到通知的作用,不会释放锁标记

注意:调用 wait方法的对象和调用notify的对象是同一对象 (临界资源)

整理不易,喜欢请点个赞!

编者微信:1014961803,添加时请备注"CSDN"

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。