java学习(16)
来源:互联网 发布:半结构化数据 编辑:程序博客网 时间:2024/06/15 10:05
java学习(16)
这篇接着来写多线程的内容,包括一些线程的方法,线程组、线程池以及关于定时
器的介绍。
1.线程中部分方法
1.1 线程加入
public final void join():等待该线程中止,其他线程才能继续抢着执行
public class Mythread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i%2==0){System.out.println(this.getName()+"="+i);}}}}public static void main(String[] args) {//1.1 线程加入 //public final void join() //等待该线程中止,其他线程才能继续抢着执行//创建三个线程Mythread mt1 = new Mythread();Mythread mt2 = new Mythread();Mythread mt3 = new Mythread();//给三个线程设置名字mt1.setName("mt1");mt2.setName("mt2");mt3.setName("mt3");mt1.start();try {mt1.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//启动线程mt2.start();mt3.start();}
分析:使用了join()方法,只有线程mt1运行中止,线程mt2和mt3才能抢占CPU执行
1.2 线程礼让
public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 50; i++) {if(i%3==1){System.out.println(this.getName()+"***"+i);}Thread.yield();}}}public static void main(String[] args) {//创建三个线程MyThread mt1 = new MyThread();MyThread mt2 = new MyThread();MyThread mt3 = new MyThread();//设置名字mt1.setName("mt1");mt2.setName("mt2");mt3.setName("mt3");//启动线程mt1.start();mt2.start();mt3.start();}分析:线程礼让难以实现线程之间的和谐运行
1.3 线程死亡
public final void stop():直接杀死
public void interrupt():直接杀死,在死前,还可以有遗言
public static void main(String[] args) {//创建一个线程MyThread mt = new MyThread();//启动线程mt.start();try {Thread.sleep(3000);//public final void stop():直接杀死//mt.stop();//interrupt():直接杀死,在死前,还可以有遗言。mt.interrupt();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}注意:这里使用stop()方法的时候,代码上会有一天直线,表示该方法已经过时,但还可以使用。stop()和interrupt()方法的区别在于stop是立即结束该进程,不会有停留,interrupt立即结束进程,但是还可以执行一段代码。
1.4 线程休眠
static void sleep(long millis) 线程睡一会
分析:该方法已经多次使用,可以查看上述代码。
2.线程的生命周期
1)新建
2)就绪
3)运行
4)有可能阻塞
5)死亡
3.线程间通信(生产消费者问题):不同类型线程针对同一个资源的操作
案例详细解析:例如给学生设置和获取姓名和年龄
线程间通讯:
1)资源:Student
2)设置数据线程:SetThread
3)获取数据线程:GetThread
代码:
public class GetThread implements Runnable{private Student s;public GetThread(Student s){this.s = s;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {synchronized(s){System.out.println(s.name+":"+s.age);}}}}
public class SetThread implements Runnable{private Student s;int x = 0;public SetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){synchronized(s){if(x%2==0){s.name = "student1";s.age = 12;}else{s.name = "student2";s.age = 21;}x++;}}}}
public class Student { String name; int age;}
public class Test {public static void main(String[] args) {//创建一个学生对象Student s = new Student();//创建设置线程和获取线程对象SetThread st = new SetThread(s);GetThread gt = new GetThread(s);//创建线程Thread thread1 = new Thread(st);Thread thread2 = new Thread(gt);//启动线程thread1.start();thread2.start();}}分析:如上代码运行,
问题1:对于控制台出现的结果是:null:0
是由于设置和获取线程使用的学生资源不是同一个,可以把资源作为构造参数传递
问题2:相同的数据出现了多次以及数据安全问题
CPU的一点点时间片就足够我们的程序执行很多次,要加锁
问题3:加了锁以后,数据还是有问题
多个线程都要加锁;多个线程加的锁必须是同一把锁
4.线程组改进代码:
public class GetThread implements Runnable{private Student s;public GetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){synchronized (s) {if(!s.flag){try {s.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(s.name+":"+s.age);//读取数据之后置flag为false,默认取出后没有数据了s.flag = false;//唤醒等待的进程s.notify();}}}}public class SetThread implements Runnable{private Student s;int x=0;public SetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){synchronized (s) {if(s.flag){try {s.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(x%2==0){s.name = "小明";s.age = 12;}else{s.name = "小红";s.age = 15;}x++;//设置数据之后置flag为trues.flag = true;//唤醒等待的进程s.notify();}}}}public class Student {//成员变量String name;int age;//用来标识有没有数据boolean flag;}public class Test {public static void main(String[] args) {//创建一个学生对象Student s = new Student();//创建设置线程和获取线程对象SetThread st = new SetThread(s);GetThread gt = new GetThread(s);//创建线程Thread thread1 = new Thread(st);Thread thread2 = new Thread(gt);//启动线程thread1.start();thread2.start();}}分析:这里的改进代码在student类里,加了一个flag成员变量,用以表示对象是否已经有数据,在设置线程和获取线程里面,进行判断以此来确定线程的执行顺序。运行:
线程组:Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
默认情况下,所有的线程都属于主线程组。
public final ThreadGroup getThreadGroup():获取线程对应的线程组对象
线程设置分组
Thread(ThreadGroup group, Runnable target)
代码:
public class MyThread extends Thread{@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();}}public static void main(String[] args) {//创建线程获取对应的线程组对象,并获取名称MyThread mt1 = new MyThread();MyThread mt2 = new MyThread();//获取上面两个线程对应的线程组对象ThreadGroup tg1 = mt1.getThreadGroup();ThreadGroup tg2 = mt2.getThreadGroup();//输出线程组名称System.out.println(tg1.getName());System.out.println(tg2.getName());}
运行:
分析:这里给出的是默认情况,线程是属于主线程组,打印出来的线程组名称是main
5.线程池
5.1为什么要使用线程池?
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
5.2线程池的特点:
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
5.3线程池的创建:
JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newFixedThreadPool(int nThreads)
5.4线程池的使用步骤:
1.创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2);
2.创建Runnable实例
MyRunnable my = new MyRunnable();
3.提交Runnable实例
pool.submit(my);
4.关闭线程池
pool.shutdown();
代码示例:
public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i%2==0){System.out.println(Thread.currentThread().getName()+"=="+i);}}}}
public static void main(String[] args) {//1.创建线程池对象//ExecutorService pool = Executors.newFixedThreadPool(2);ExecutorService pool = Executors.newFixedThreadPool(2);//2.创建Runnable实例//MyRunnable my = new MyRunnable();MyRunnable my1 = new MyRunnable();MyRunnable my2 = new MyRunnable();//3.提交Runnable实例//pool.submit(my);pool.submit(my1);pool.submit(my2);//4.关闭线程池//pool.shutdown();pool.shutdown();}运行:
分析:这里给出的代码是实现了Runnable接口,如果有返回值则可以实现Callable接口来实现线程池。
6.定时器 Timer
public Timer()构造
TimerTask
public abstract void run()放的是所要执行的任务代码
public boolean cancel()取消这个任务
public void schedule(TimerTask task, long delay)延迟多久执行任务
public class TimerTest01 {public static void main(String[] args) {//创建一个定时器Timer t = new Timer();//public void schedule(TimerTask task, long delay)延迟多久执行任务t.schedule(new Task(), 2000);}}class Task extends TimerTask{@Overridepublic void run() {System.out.println("to be or not bo be");}}
分析:延迟指定的时间执行Task里run方法的代码
public void schedule(TimerTask task,long delay,long period)延迟多久执行任务,并以后每隔多久执行一次
public class TimerTest02 {public static void main(String[] args) {//创建一个定时器Timer t = new Timer();//public void schedule(TimerTask task,long delay,long period)//延迟多久执行任务,并以后每隔多久执行一次t.schedule(new Task2(), 2000,1000);}}class Task2 extends TimerTask{@Overridepublic void run() {System.out.println("to be or not bo be");}}运行:
分析:
三个参数:
参数1:要执行的任务
参数2:延迟多久执行
参数3:执行一次之后,每隔多久重复执行
- java学习(16)
- java学习(16)
- 【java】java学习(一)
- 【java】java学习(二)
- Java学习笔记18天---(16)
- 我的java学习日记(16)
- Java学习笔记16
- java学习笔记16
- Java学习笔记16
- Java学习-16天
- Java学习16 线程
- java学习总结(16.05.16) java的修饰符
- java并发编程实践学习(16)Java存储模型
- Java学习(途径!)
- 学习JAVA(一)
- 学习Java(一)
- java学习(1)
- java学习(2)
- java中关于File类的使用
- ReactNative仿《ONE》APP
- (56)组件之paper2D组件
- 代理服务器理解
- 利用RedHat6.6光盘来重新安装python和yum
- java学习(16)
- Ionic2升级到Ionic3
- 一天一条shell命令----------expr命令
- Facebook Software Engineer 电面面经
- 循环链表学习笔记
- java学习(17)
- MaterialDesign之学一波Palette
- (57)组件之物理组件
- HashMap详解