JAVA-16.1-线程常用方法、线程生命周期、线程组、线程池、计时器
来源:互联网 发布:如何自学软件编程 编辑:程序博客网 时间:2024/05/20 03:44
一:线程中的一些方法(线程中存在的现象)
1.1 线程加入
public final void join()
等待该线程运行完毕,然后剩下的线程再一起抢占CPU执行权
package com.edu.exercise_01;public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(getName()+" "+i); } }}
package com.edu.exercise_01;/** * 1.1 线程加入 public final void join() 等待该线程中止,其他线程才能继续抢着执行 */public class Test { public static void main(String[] args) throws Exception { MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); MyThread mt3 = new MyThread(); mt1.setName("张三"); mt2.setName("李四"); mt3.setName("王五"); mt1.start(); mt1.join(); mt2.start(); mt3.start(); }}//运行结果://张三 0//张三 1//张三 2//张三 3//张三 4//李四 0//李四 1//李四 2//王五 0//李四 3//王五 1//李四 4//王五 2//王五 3//王五 4
1.2 线程礼让
public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
作用:让线程间的执行更和谐一些,但是实际上做不到。可以通过后面讲解的知识来实现。
package com.edu.exercise_02;public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName()+" "+i); //实现线程礼让 //public static void yield():暂停当前正在执行的线程对象,并执行其他线程。 //作用:让线程间的执行更和谐一些,但是实际上做不到 Thread.yield(); } }}
package com.edu.exercise_02;public class Test { public static void main(String[] args) { MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); MyThread mt3 = new MyThread(); mt1.setName("小张"); mt2.setName("小李"); mt3.setName("小王"); mt1.start(); mt2.start(); mt3.start(); }}
1.3 线程死亡
public final void stop():直接杀死被清理掉
public void interrupt():直接杀死,被清理之前前,会将剩下的代码执行完毕。
package com.edu.exercise_03;import java.text.SimpleDateFormat;import java.util.Date;public class MyThread extends Thread{ @Override public void run() { //获取开始时间 System.out.println("StartTime:"+new SimpleDateFormat("HH:mm:ss").format(new Date())); //休眠10秒 try { Thread.sleep(10000); } catch (InterruptedException e) { System.out.println("被终止了"); } //获取结束时间 System.out.println("EndTime:"+new SimpleDateFormat("HH:mm:ss").format(new Date())); }}
package com.edu.exercise_03;/** * 1.3 线程死亡 public final void stop():直接杀死(被清理) public void interrupt():直接杀死,在被清理之前会将剩下的代码执行完毕,然后才被清理 * */public class Test { public static void main(String[] args) { //创建线程对象 MyThread mt = new MyThread(); //开启线程对象 mt.start(); //主线程休眠3秒,睡眠的过程中将mt线程杀死 try { Thread.sleep(3000); mt.interrupt();//首先输出StartTime:08:54:40 //3秒后输出: /** 被终止了 EndTime:08:54:43 */ } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }/* //主线程休眠3秒,睡眠的过程中将mt线程杀死 try { Thread.sleep(3000); mt.stop();//首先输出StartTime:08:57:13 //3秒后输出结果只有StartTime:08:48:50,并且终止线程 //stop划了一条横线表示该方法已经过时,但是还可以使用 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ }}
1.4 线程休眠
static void sleep(long millis) 线程睡眠
二:线程的生命周期(画图讲解),面试题
1.新建
2.就绪
3.运行
4.有可能阻塞
5.死亡
三:线程组
3.1线程组:Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
注意:默认情况下,所有的线程都属于主线程组。
3.2线程组使用的一般步骤:
① a. 如果是给线程分组、命名,则首先创建MyRunnable类实现Runnable接口,重写run()方法;
b. 如果是仅仅获取线程名称等,可以创建MyThread类继承Thread类,重写run()方法。
②创建线程组,并给线程组取名字
ThreadGroup tg = new ThreadGroup(“我的线程组”);
③给线程设置分组
a. MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(tg, mr);
或者:
b. Thread t2 = new Thread(tg, new MyRunnable());
④获取线程组对象
ThreadGroup tg1 = t1.getThreadGroup();
⑤获取线程组对象的名称
String name = tg1.getName()
案例1:创建线程获取对应的线程组对象,并获取名称
package com.edu.exercise_04;public class MyExtends extends Thread{ @Override public void run() { }}
package com.edu.exercise_04;/** 案例1:创建线程获取对应的线程组对象,并获取名称 * * 1.默认情况下,所有的线程都属于主线程组。 2. public final ThreadGroup getThreadGroup():获取线程对应的线程组对象 3. 线程组对象掉用getName(),获取线程组对象的名称,返回值是String * */public class TestExtends { public static void main(String[] args) { //创建2个线程 MyExtends mt1 = new MyExtends(); MyExtends mt2 = new MyExtends(); //获取线程的线程组对象 ThreadGroup tg1 = mt1.getThreadGroup(); ThreadGroup tg2 = mt2.getThreadGroup(); //获取线程组对象的名称 System.out.println(tg1.getName());//main System.out.println(tg2.getName());//main }}
案例2:创建线程组对象,给线程分配线程组
package com.edu.exercise_04;public class MyRunnable implements Runnable{ @Override public void run() { }}
package com.edu.exercise_04;/** 案例2:创建线程组对象,给线程分配线程组 * * 构造一个新线程组 public ThreadGroup(String name) * 给线程设置分组 Thread(ThreadGroup group, Runnable target),注意需要的是实现Runnable接口的实现类对象 */public class TestRunnable { public static void main(String[] args) { //创建实现类对象 MyRunnable mr = new MyRunnable(); //构造一个新线程组 public ThreadGroup(String name) ThreadGroup tg = new ThreadGroup("我的线程组"); //给线程设置分组 Thread(ThreadGroup group, Runnable target) Thread t1 = new Thread(tg, mr); Thread t2 = new Thread(tg, new MyRunnable()); //获取线程名称 System.out.println(t1.getThreadGroup().getName());//我的线程组 System.out.println(t2.getThreadGroup().getName());//我的线程组 }}
四:线程池
4.1为什么要使用线程池?
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
线程池的特点:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
线程池如何创建?JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法public static ExecutorService newFixedThreadPool(int nThreads)
4.2线程池的使用步骤:
①创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2);
②创建Runnable实例或者Callable实例
(创建Runnable实例,重写run()方法,没有返回值;或者创建Callable<>实例重写call()方法,有返回值,返回值类型必须是引用类型)
MyRunnable my = new MyRunnable();
③提交Runnable实例
pool.submit(my);
④关闭线程池
pool.shutdown();
案例1:实现Runnable接口实现线程池的使用
package com.edu.exercise_05;public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName()+"---"+i); } }}
package com.edu.exercise_05;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class MrThreadPool { public static void main(String[] args) { //案例1:实现Runnable接口实现线程池的使用 //1.创建线程池对象 //ExecutorService pool = Executors.newFixedThreadPool(3); ExecutorService mrpool = Executors.newFixedThreadPool(2); //2.提交给线程池两个任务,都是打印0-99 //创建Runnable实例, //MyRunnable my = new MyRunnable(); MyRunnable mr1 = new MyRunnable(); MyRunnable mr2 = new MyRunnable(); //3.提交任务 mrpool.submit(mr1);//一旦提交任务,就会自动开启线程,并执行run()方法中的代码, //每个线程任务执行完毕,线程会自动关闭,但是并没有被终止, //而是再次再次回到线程池中成为空闲状态,等待下一个对象来使用。 mrpool.submit(mr2); //关闭线程池 //void shutdown() mrpool.shutdown(); }}
案例2:实现Callable接口实现线程池的使用
package com.edu.exercise_05;//Callable接口和Runnable接口很相似,不同的是前者有返回值,后者没有返回值import java.util.concurrent.Callable;public class MyCallable implements Callable{ @Override public Object call() throws Exception { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName()+"---"+i); } return null; }}
package com.edu.exercise_05;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class McThreadPool { public static void main(String[] args) { //案例2:实现Callable接口实现线程池的使用 //1.创建线程池 ExecutorService mcpool = Executors.newFixedThreadPool(2); //2.创建任务 MyCallable mc1 = new MyCallable(); MyCallable mc2 = new MyCallable(); //3.提交任务 mcpool.submit(mc1); mcpool.submit(mc2); //4.关闭线程池 mcpool.shutdown(); }}
案例3:实现Callable接口实现线程池的使用,实现多线程求和,1-10之和,1-100之和
package com.edu.exercise_06;//实现Callable接口实现线程池的使用,实现多线程求和,1-10之和,1-100之和import java.util.concurrent.Callable;/** * 要想在主函数中直接给MyCallable类初始化,把开始值和结束值传进来,就应该想到利用构造方法传参 * */public class MyCallable implements Callable<Integer>{ private int start; private int end; public MyCallable(int start , int end){ this.start = start; this.end = end; } @Override public Integer call() throws Exception { //求和 int sum = 0; for (int i = start; i < end + 1; i++) { sum+=i; } return sum; }}
测试类:
package com.edu.exercise_06;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class Test { public static void main(String[] args) throws Exception { //1.创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2); //2.创建任务 MyCallable mc1 = new MyCallable(1, 10); MyCallable mc2 = new MyCallable(1, 100); //3.添加任务 Future<Integer> res1 = pool.submit(mc1); Future<Integer> res2 = pool.submit(mc2); //V get()如有必要,等待计算完成,然后获取其结果。 System.out.println(res1.get()); System.out.println(res2.get()); //4.关闭线程池 pool.shutdown(); }}
五:定时器
①Timer类
public Timer()构造
public void schedule(TimerTask task, long delay)延迟多久执行任务
public void schedule(TimerTask task,long delay,long period)延迟多久执行任务,并以后每隔多久执行一次
public void schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务
public boolean cancel()取消这个任务
②TimerTask抽象类,用于创建一个计时任务
public abstract void run()放的是所要执行的任务代码
案例1:演示以上方法的使用
package com.edu.exercise_07;import java.util.Timer;import java.util.TimerTask;//需求:在5秒钟后,在控制台打印一句话,helloworldpublic class TimerTest { public static void main(String[] args) { Timer t = new Timer(); //public void schedule(TimerTask task, long delay)延迟多久执行任务 //TimerTask是抽象类 t.schedule(new MyTimerTask(t), 5000); //t.cancel();//如果在这里关闭的话,我们还没等任务执行完毕呢,计时器已经被关闭了 }}class MyTimerTask extends TimerTask{ private Timer t; public MyTimerTask(Timer t){ this.t = t; } @Override public void run() { System.out.println("helloworld"); t.cancel();//等待任务结束,将计时任务取消 }}
案例2:定时删除文件
package com.edu.exercise_08;import java.io.File;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class Test { public static void main(String[] args) throws Exception { /** * 案例:定时删除文件(需要在指定时间删除D://a.txt文件) * 所用方法:schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务 * 时间点:16:30:00 * 任务:删除D://a.txt文件 */ //1.创建定时器 Timer t = new Timer(); //2.指定的时间解析为日起对象 String time = "2017-05-21 16:31:00"; Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(time); //3.所用方法:schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务 t.schedule(new MyTimerTask(t), date); }}class MyTimerTask extends TimerTask{ //构造传参 private Timer t; public MyTimerTask(Timer t) { this.t = t; } @Override public void run() { //任务:删除D://a.txt文件 File file = new File("D://a.txt"); file.delete(); t.cancel(); } }
- JAVA-16.1-线程常用方法、线程生命周期、线程组、线程池、计时器
- java线程池 常用方法
- java线程池 常用方法
- 【Java】线程常用方法
- 线程计时器
- Java--线程生命周期,线程控制
- 线程池的计时器
- 线程池计时器
- 线程生命周期与线程池
- 线程入门学习3-------线程的生命周期和常用方法
- 13.6 线程的生命周期状态,线程常用的方法
- java常用线程池
- java常用线程池
- Java 常用线程池
- 《Java线程池》:Executor生命周期
- 《Java线程池》:Executor生命周期
- 线程的生命周期与常用方法
- Java线程:线程池
- 生成人脸修复模型:同时使用两个鉴别器,直接合成逼真人脸
- php合并数组的两种方式
- leetcode 274. H-Index
- hql由于关键字报错
- vi编辑器【常用操作】
- JAVA-16.1-线程常用方法、线程生命周期、线程组、线程池、计时器
- beego如何获取客户端IP?
- Cordova cordova_sqlite_storage控件的使用
- C#----小知识
- Java实现寻找链表的中间节点
- 服务器常用端口介绍
- 剑指Offer-8
- Python三大神器之pip的安装
- 【git系列之E】git的分支操作(查看分支、切换分支、新建分支和删除分支)