本文共 6543 字,大约阅读时间需要 21 分钟。
Java多线程:java语言的一个优势就是处理多线程简单
在一个操作系统中会同时运行多个任务(程序),例如:QQ、微信等 1.在操作系统中同时运行的每一个任务都是一个进程 2.对于一个进程(程序)而言,在程序内部也会同时运行多个任务,那个每一个任务称为一个线程 线程的运行都是并发执行的,所谓的并发:宏观上所有的线程都是同时执行的,但是微观上所有的线程都是"走走停停" 线程的调度: 将CPU的时间划分为若干个时间片段,尽可能的均匀分配给每一个线程,获得CPU时间片段的线程将得以CPU执行 创建线程的两种方式:Thread类 线程类 其每一个实例表示一个可以并发的线程(匿名内部类) 使用线程的注意事项: 对于线程调度而言,分配的时间片段长短,具体分配给哪一个线程时间片段,对于程序而言,都是不可控制的 * 使用多线程不考虑执行的先后顺序问题 * 执行没有先后顺序的是异步运行(并发运行)--登录 * 执行有先后顺序的是同步运行--银行取钱 第一种创建线程的方式:继承Thread类 第一种创建线程的方式存在弊端: * 线程与线程要干的事情(任务)耦合在一起 * --启动线程是调用start方法,自动执行run方法 *继承只能单继承 第二种创建线程的方式:实现Runnable接口 --将任务和线程解耦线程在执行某段逻辑时可以发生阻塞现象(控制自己不被执行)
sleep阻塞: 该阻塞可以指定阻塞时间,并在线程阻塞了该时间后自动返回runnable等待方法,Thread提供了一个静态方法sleep()用于睡眠阻塞 线程阻塞在以下情况可以停止: 1、run方法正常执行完毕 2、run方法执行过程中抛出了一个未捕获的异常 进程的停止: 当一个进程中所有前台线程停止后,该进程结束 前台线程和后台线程 后台线程的特点:用法与前台线程无异,只是当一个进程中所有前台线程都结束后, 无论后台线程是否还在运行中都被强制结束,从而使得进程结束,程序退出 后台线程:也称为守护线程,或者精灵线程---lol开挂刷野时间盒 设置后台线程 设置后台线程方法要在该线程被调用start()之前调用 zhou.setDaemon(true); 在运行我们的程序时,操作系统会启动一个进程来运行JVM,JVM运行后会创建第一个前台 线程来运行我们的程序的main方法,同时也会创建一个后台线程来运行GC(垃圾回收机制)线程的优先级:1-10(1最低、10最高)
优先级越高的线程被分配时间片段的机会就越多,那么CPU执行的机会就越多 线程安全: 多线程并发访问同一资源时,会产生线程安全问题 解决办法:并发即异步---将异步操作变成同步操作 1、多线程并发读写同一临界资源会发生“线程安全并发问题” 如果保证多线程同步访问临界资源,就可以解决安全问题。 2、常见的临界资源: 多线程共享的实例变量、静态的公共变量 3、异步:各干各的 执行没有先后顺序 AJax 同步:你干完我再干 执行有先后顺序 4、同步锁:关键字synchronized----重要!!! synchronized可以修饰方法,当一个方法被修饰后,这个方法就是同步方法,同一刻只有一个线程访问该方法 synchronized块 当一个方法被修饰后,该方法变成同步方法,虽然保证了代码的执行安全,但是效率 低下,我们实际上只需要将方法需要的同步片段加锁,这样可以缩小同步范围,从而 提高代码的运行效率 语法: synchronized(同步监视器){ 需要同步的代码片段 } 同步监视器:就是一个对象,任何对象都可以,可以new Object() 但要保证一点,多线程看到的应该是"同一个"对象,通常情况下使用this非线程安全 线程安全
StringBuilder StringBuffer ArrayList Vector HashMap HashTable HashSet ...... 对于集合Collection和Map而言 Collections类提供了可以将给定的集合转换为线程安全的集合方法 list = Collections.synchronizedList(list);线程的协调工作:
download.join(); //先执行download线程 wait-notify 使用wait()和notify()完成线程的协同工作 * wait()阻塞会在以下两种情况被解除 * 1.当download线程结束 * 2.当调用了download的notify() * ---属于Object方法 synchronized(object){ object.wait(); synchronized(object){ //通知object身上的等待的线程解除阻塞 object.notify(); }Day05
总结--创建线程的方式: 1、继承Thread类 实体类继承Thread类,覆盖run()方法,提供并发运行的过程 创建这个类的实例 使用start()启动线程 2、实现Runnable接口 3、使用内部类/匿名内部类创建线程 线程的状态 1、new 新建状态,还未启动 2、Runnable 等待状态,可以运行状态(就绪) 3、Ruuning 正在运行的状态,该线程已经获得了CPU a.假设线程获取了CPU,则进入Running状态,开始执行线程体 b.假设系统只有一个CPU那么在任意时间点,只有一个线程属于Running 如果是双核,那么在同一时间点,那么会有两条线程处于Running,但是当线程数大于处理器,依然会是多条线程在同一CPU轮换执行 c.当一条线程开始运行的时候,如果不是一瞬间完成,那么它不可能一直处于 Running状态,线程会在执行过程中被中断,目的是为了让其他线程获得执行机会,像这样的线程调度的策略取决于底层平台,对于抢占式策略的平台来说, 系统会给每个可执行的线程一小段时间来处理任务,当该时间片段用完了,系统会剥夺线程所占资源(CPU),让其他线程获得运行机会 4、block 阻塞或者挂起状态 a.以下情况会发生阻塞状态 1.线程使用了sleep() 2.线程调用了阻塞式IO方法(比如控制台输入方法),在该方法放回前,该线程被阻塞 3.join wait-notify b.当正在执行的线程被阻塞时,其他线程就获得机会,阻塞结束的时候,该线程 进入Runnable等待状态,而非直接进入Running状态 5、dead 死亡状态 run()执行结束,该线程进入死亡状态,不要试图对一个已经死亡的线程调用 start(),死亡后不能再次作为线程执行,会抛出异常 线程的状态管理: 1、Thread.sleep(times) 使当前线程从Running放弃处理器进入block状态,休眠times毫秒,再返回Runnable状态,如果其他线程打断了当前线程的Block(sleep) 就会发生中断异常InterruptedException 2、Thread.yield() 让出CPU,当线程让出处理器(离开Running),进入Runnable状态 线程的常用属性和方法: 1.线程的优先级 setPriorty 2.后台线程(守护线程) 线程对象引用名.setDaemon(true) 3.获取线程的名字 getName() 4.获取当前线程 Thread.currentThread() 5.sleep状态的打断和唤醒 Thread.sleep(times) 引用名.interrupt() 被唤醒的线程会出现中断异常 线程池:Java1.5提供了并发包concurrent Executors是工厂,包含工厂用于创建Executor接口的实例 Executor threadPools=Executors.newFixedThreadPool(2); Process p1=new Process(); threadPools.execute(p1);//执行创建线程的两张方式:
package day04;//第一种创建线程的方式:继承Thread类public class ThreadDemo01 { public static void main(String[] args) { Thread t1=new Person1(); Thread t2=new Person2(); //启动线程是调用start方法,自动执行run方法 t1.start(); t2.start(); /* * 使用多线程不考虑执行的先后顺序问题 * 执行没有先后顺序的是异步运行(并发运行)--登录 * 执行有先后顺序的是同步运行--银行取钱 */ } /* * 第一种创建线程的方式存在弊端: * 线程与线程要干的事情(任务)耦合在一起 * --启动线程是调用start方法,自动执行run方法 */}class Person1 extends Thread{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("你是谁啊"); } }}class Person2 extends Thread{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("我是收电费的"); } }}
package day04;//第二种创建线程的方式:实现Runnable接口//将任务和线程解耦public class ThreadDemo02 { public static void main(String[] args) { //创建线程时再将任务指派 Thread t1=new Thread(new PersonOne()); Thread t2=new Thread(new PersonTwo()); t1.start(); t2.start(); }}class PersonOne implements Runnable{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("你是谁啊"); } }}class PersonTwo implements Runnable{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("查水表的"); } }}
多线程Join:
package day04;//线程的协调工作public class JoinThreadDemo { //图片是否下载完毕 public static boolean isFinish = false; public static void main(String[] args) { //下载图片的线程 final Thread download = new Thread(){ public void run(){ System.out.println("download:开始下载图片"); for(int i=0;i<=100;i++){ System.out.println("download:已完成"+i+"%"); try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } System.out.println("download:图片下载完毕"); isFinish = true;//表示图片下载完毕 } }; //显示图片的线程 Thread showImg = new Thread(){ public void run(){ System.out.println("showImg:准备显示图片"); //等待下载线程工作结束后,再执行下面的代码 try { //先执行download download.join(); } catch (Exception e) { e.printStackTrace(); } if(!isFinish){ throw new RuntimeException("图片没有下载完毕"); } System.out.println("showImg:图片已经显示了"); } }; showImg.start(); download.start(); }}
多线程wait()...notify()
package day05;//使用wait()和notify()完成线程的协同工作public class WaitAndNotifyDemo { public static boolean isFinish = false; public static Object object=new Object(); public static void main(String[] args) { //下载图片的线程 final Thread download = new Thread(){ public void run(){ System.out.println("download:开始下载图片"); for(int i=0;i<=100;i++){ System.out.println("download:已完成"+i+"%"); try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } System.out.println("download:图片下载完毕"); isFinish = true;//表示图片下载完毕 synchronized(object){ //通知object身上的等待的线程解除阻塞 object.notify(); } } }; //显示图片的线程 Thread showImg = new Thread(){ public void run(){ System.out.println("showImg:准备显示图片"); //等待下载线程工作结束后,再执行下面的代码 try { /* * wait()阻塞会在以下两种情况被解除 * 1.当download线程结束 * 2.当调用了download的notify() * ---属于Object方法 */ synchronized(object){ object.wait(); } } catch (Exception e) { e.printStackTrace(); } if(!isFinish){ throw new RuntimeException("图片没有下载完毕"); } System.out.println("showImg:图片已经显示了"); } }; download.start(); showImg.start(); } }
转载地址:http://wgpqb.baihongyu.com/