本文共 8380 字,大约阅读时间需要 27 分钟。
【JavaSE】day13_多线程
1)线程
* 并发运行,可以"同时"完成多个任务。
2)线程有两种创建模式
* 模式1:
* 定义一个类并继承Thread,然后重写run方法,在内部编写该程序要执行的任务。
3)注意!启动线程不要直接调用run方法。而是调用start方法。
* 该方法会将当前线程注册到线程调度中,使其可以并发运行。start方法调用完毕后意味着当前线程进入了runnable状态,一旦被线程调度分配时间片就开始运行。
* 线程对于线程调度的工作不可控:
* CPU时间片分配给哪个线程不可控。
* 时间片长短不可控。
* 不过线程调度会尽可能的均匀的将时间片分配给每个线程。
代码演示:
package day04;/** * 线程 * 并发运行,可以"同时"完成多个任务。 * * 线程有两种创建模式 * 模式1: * 定义一个类并继承Thread,然后重写run方法,在内部编写该程序 * 要执行的任务。 * */public class ThreadDemo1 { public static void main(String[] args) { Thread t1 = new MyThread1(); Thread t2 = new MyThread2(); /* * 注意!启动线程不要直接调用run方法。而是调用start方法。 * 该方法会将当前线程注册到线程调度中,使其可以并发运行。 * start方法调用完毕后意味着当前线程进入了runnable状态, * 一旦被线程调度分配时间片就开始运行。 * * 线程对于线程调度的工作不可控: * CPU时间片分配给哪个线程不可控。 * 时间片长短不可控。 * * 不过线程调度会尽可能的均匀的将时间片分配给每个线程。 */ t1.start(); t2.start(); }}/* * 第一种创建线程的方式存在两个弊端: * 1:由于java是单继承的,所以若我们继承了Thread就无法继承 * 其他类,这对于项目开发而言是不可容忍的。 * 2:重写run方法会导致线程与线程要执行的任务有一个耦合关系, * 这导致当前线程只会完成该任务,不利于线程的重用。 * 第一种创建线程也存在一个优点: * 定义简便。当我们需要临时使用一个线程完成某个任务时通常会使用 * 匿名内部类,这时用第一种方式创建比较理想。 */class MyThread1 extends Thread{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("你是谁?"); } }}class MyThread2 extends Thread{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("我是查水表的"); } }}
package day04;/** * 线程的第二种创建模式: * 1:单独定义线程要执行的任务 * 定义一个类,实现Runnable接口,并重写run方法 * 2:创建线程并将任务指派进去再启动。 * * 优点: * 1:单独定义任务,在用的时候才指派线程,所以与线程 * 没有必然的耦合关系,利于线程重用。 * 2:由于任务类是实现Runnable接口,java接口是多实现的, * 所以无论是继承其他类还是实现其他接口都不再受影响。 */public class ThreadDemo2 { public static void main(String[] args) { //创建任务 Runnable runn1 = new MyRunnable1(); Runnable runn2 = new MyRunnable2(); //创建线程,并指派任务给线程 Thread t1 = new Thread(runn1); Thread t2 = new Thread(runn2); //启动线程 t1.start(); t2.start(); }}class MyRunnable1 implements Runnable{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("你是谁啊"); } }}class MyRunnable2 implements Runnable{ public void run(){ for(int i=0;i<1000;i++){ System.out.println("我是查水表的"); } }}
package day04;/** * 练习使用匿名内部类的形式创建线程 */public class ThreadDemo3 { public static void main(String[] args) { //第一种创建模式 Thread t1 = new Thread(){ public void run(){ for(int i=0;i<1000;i++){ System.out.println("你是谁啊"); } } }; //第二种创建模式 Runnable runn = new Runnable(){ public void run(){ for(int i=0;i<1000;i++){ System.out.println("我是查水表的"); } } }; Thread t2 = new Thread(runn); t1.start(); t2.start(); }}
package day04;/** * Thread提供了一个静态方法currentThread, * 该方法可以获取运行这个方法的线程。 * * 实际上main方法也是靠一个线程运行的,只是该 * 线程不是由我们直接创建的。 * */public class ThreadDemo4 { public static void main(String[] args) { //获取运行main方法的线程 Thread t = Thread.currentThread(); System.out.println(t); dosome(); Thread my = new Thread(){ public void run(){ Thread t = Thread.currentThread(); System.out.println(t); //自定义线程my dosome(); } }; my.start(); } public static void dosome(){ Thread t = Thread.currentThread(); System.out.println("dosome:"+t); }}
package day04;/** * 获取线程状态的相关方法 * */public class ThreadDemo5 { public static void main(String[] args) { Thread t = Thread.currentThread(); //获取线程id System.out.println("id:"+t.getId()); //获取线程名字 System.out.println("name:"+t.getName()); //获取线程优先级 System.out.println("priority:"+t.getPriority()); //获取是否活着 System.out.println("isAlive:"+t.isAlive()); //是否为后台线程 System.out.println("isDaemon:"+t.isDaemon()); //是否被中断了 System.out.println("isInterrupted:"+t.isInterrupted()); }}
package day04;/** * 线程优先级 * 优先级有10个等级,1-10,其中1最低,10最高,默认为5 * 有三个常量可以对应最低,最高,默认优先级 * Thread.MIN_PRIORITY ==> 1 * Thread.MAX_PRIORITY ==> 10 * Thread.NORM_PRIORITY ==> 5 * */public class ThreadDemo6 { public static void main(String[] args) { Thread min = new Thread(){ public void run(){ for(int i=0;i<10000;i++){ System.out.println("min"); } } }; Thread max = new Thread(){ public void run(){ for(int i=0;i<10000;i++){ System.out.println("max"); } } }; Thread norm = new Thread(){ public void run(){ for(int i=0;i<10000;i++){ System.out.println("norm"); } } }; min.setPriority(Thread.MIN_PRIORITY); max.setPriority(10); min.start(); norm.start(); max.start(); }}
package day05;import java.text.SimpleDateFormat;import java.util.Date;/** * Thread提供了一个静态方法sleep,该方法可以使运行该方法的线程阻塞 * 指定毫秒。当阻塞时间超时后,该线程会自动回到runnable状态,等待再 * 次分配时间片然后运行。 * */public class ThreadDemo1 { public static void main(String[] args) { /* * 电子表,每秒钟输出当前系统时间:HH:mm:ss */ Date date = null; SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); while(true){ date = new Date(); String str = sdf.format(date); System.out.println(str); try { /* * sleep做不到严格意义上的间隔 * 可以保证1秒的阻塞,但是解除阻塞后线程回到runnable状态, * runnable到run这个等待时间就是误差。 */ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }}
package day05;/** * 守护线程,又称后台线程 * 当一个进程中的所有前台线程都结束时,进程就要结束, * 无论后台线程是否还处于运行状态,都要强制中断。 */public class ThreadDemo2 { public static void main(String[] args) { //rose:前台线程 Thread rose = new Thread(){ public void run(){ for(int i=0;i<10;i++){ System.out.println("rose:let me go!"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("......"); } }; //jack:后台线程 Thread jack = new Thread(){ public void run(){ while(true){ System.out.println("jack:you jump!i jump!"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; rose.start(); //设置为后台线程,在start前设置 jack.setDaemon(true); jack.start(); }}
package day05;/** * join方法 * join方法会阻塞运行该方法的线程,允许该线程在另一个 * 线程上等待,直到那个线程的工作结束,当前线程才会解除 * 阻塞继续运行。 * 该方法通常为了实现两个线程间同步(有先后顺序工作)的情况。 * */public class ThreadDemo3 { //标示图片是否下载完毕 public static boolean isFinish; 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+=10){ System.out.println("download:"+i+"%"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("download:下载完毕!"); isFinish = true; } }; /* * 显示线程 */ Thread show = new Thread(){ public void run(){ System.out.println("show:开始显示图片!"); /* * 显示之前应该等待下载完毕! */ try{ /* * 一个方法中的局部内部类中若想引用这个方法的其他 * 局部变量,那么这个变量必须是final的。 */ download.join(); }catch(InterruptedException e){ e.printStackTrace(); } if(!isFinish){ /* * 当线程抛出一个未捕获的异常时,该线程直接被kill */ throw new RuntimeException("图片显示失败"); } System.out.println("图片显示完毕!"); } }; download.start(); show.start(); }}
package day05;/** * object中定义了两个方法wait,notify * 当一个线程调用了一个对象的wait方法后,该线程进入阻塞状态, * 直到这个对象的notify方法被调用才可以解除阻塞.对于协调 * 线程同步而言,这种方式比join的即时性强,因为join必须被动 * 的等待其他线程完成所有工作. * */public class ThreadDemo4 { //标示图片是否下载完毕 public static boolean isFinish; public static Object obj = 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+=10){ System.out.println("download:"+i+"%"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("download:图片下载完成"); isFinish = true; //当图片下载完毕,就可以通知显示线程显示图片了。 synchronized(obj){ obj.notify(); } //下载附件 System.out.println("开始下载附件..."); for(int i=0;i<=100;i+=20){ System.out.println("download:"+i+"%"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("download:附件下载完毕"); } }; /* * 显示线程 */ final Thread show = new Thread(){ public void run(){ System.out.println("开始显示图片..."); try { synchronized(obj){ obj.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } if(!isFinish){ throw new RuntimeException("show error"); } System.out.println("图片显示完毕"); } }; download.start(); show.start(); }}
转载地址:http://rrews.baihongyu.com/