通过任务管理器,我们就看到了进程的存在
而通过观察,我们发现只有运行的程序才会出现进程。
所以进程:就是正在运行的程序。是系统进行资源分配和调度的独立单位。每一个进程都有它自己的内存空间和系统资源。
单进程的计算机只能做一件事情,而我们现在的计算机都可以做多件事情:一边玩游戏(游戏进程),一边听音乐(音乐进程)。
举例:一边玩游戏(游戏进程),一边听音乐(音乐进程)
也就是说现在的计算机都是支持多进程的,就可以在一个时间段内执行多个任务。
并且呢,可以提高CPU的使用率。
问题:一边玩游戏,一边听音乐是同时进行的吗?不是。因为单CPU在某一个时间点上只能做一件事情。而我们在玩游戏,或者听音乐的时候,是CPU在做着程序间的高效切换,让我们觉得是同时进行的。
在同一个进程内又可以执行多个任务,而这每一个任务我可以看做是一个线程
线程:是进程的执行单元,执行路径。是程序使用CPU的最基本单位
单线程:如果程序只有一条执行路径
多线程:如果程序有多条执行路径
多线程的存在,不是提高程序的执行速度,其实为了提高应用程序的使用率。
程序的执行其实都是在抢CPU的资源,CPU的执行权。
多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权。
我们是不敢哪一个线程能够在哪个时刻抢到,所以线程的执行有随机性。
新建:创建线程对象
就绪:有执行资格,没有执行权
运行:有执行资格,有执行权
阻塞:由于一些操作让线程处于该状态不。没有执行资格,没有执行权
而另一些操作却可以把它 给激活,激活后处于就绪状态。
死亡:线程对象变成垃圾,等待被回收
实现多线程的方式:2种
方式1:继承Thread类
A:自定义类MyThread类
B:在MyThread类中重写run()
C:创建MyThread类的对象
D:启动线程对象
问题:
a:为什么要重写run()方法?
run()方法里面封装的是被线程执行的代码
b:启动线程对象用的是哪个方法?
start()
c:run()和start()方法的区别?
run()直接调用仅仅是普通方法
start()先启动线程,再由JVM调用run()方法
代码示例:
package day23_Thread;
/** 继承类:* 该类重写run()方法,为什么呢?* 不是类中的所有代码都需要被线程执行的,而这个时候,为了区分哪些代码能够被线程执行。* java提供类Thread类中run()用来包含哪些被线程执行代码。* * */
public class MyThread extends Thread {public MyThread() {// TODO Auto-generated constructor stub}public MyThread(String name){super(name);}@Overridepublic void run() {//自己写代码//System.out.println("好好学习");//一般来说,被线程执行的代码肯定是比较耗时的,所以我们用循环改进for(int i=0;i<1000;i++){System.out.println(getName()+":"+i);}}
}
/** 名称为什么是Thread-???编号* * * */package day23_Thread;
/** 测试类:* 进程:正在运行的程序,是系统进行资源分配和调度的独立单元* 每一个进程都有它自己的内存空间和系统资源* * 线程:是进程中的单个顺序控制流,是一条执行路径* 一个进程如果只有一条执行路径,则成为单线程程序* 一个进程如果有多条执行路径,则成为多线程程序* * 举例:* 扫雷、迅雷下载* * 大家注意两个词汇的区别:并行和并发* 前者是逻辑上同时发生,指在某一个时间内同时运行多个程序* 后者是物理上同时发生,旨在某一个时间点同时运行多个程序* * Java程序运行的原理:* 由java命令启动JVM,JVM启动就相当于启动了一个进程* 接着由该进程创建了一个主线程去调用main方法。* 思考题:* jvm虚拟机的启动时单线程还是多线程的?* 多线程的。* 原因是:垃圾回收线程也要先启动,否则很容易出现内存溢出* 现在的垃圾回收线程加上主线程,最低启动了两个线程。所以,jvm的启动其实是多线程的。、* * 需求:我们要实现多线程的程序* 如何实现?* 由于线程是依赖于进程而存在的,所以我们应该先创建一个进程出来。* 而进程是由系统创建的,所以我们应该去调用系统功能去创建一个进程。* Java是不能直接调用系统功能的。所以,我们没有办法直接实现多线程程序。* 但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。* 由C/C++去调用系统功能创建进程,然后又Java去调用这样的东西。* 然后提供一些类供我们使用,我们就可以是实现多线程程序了。* 那么Java提供的类是什么呢?* Thread* 通过查看API,我们知道了有2种方式实现多线程* 方式1:继承Thread类* 步骤:* A:自定义类MyThread继承Thread类* B:MyThread类里面重写run()* 为什么是run方法呢?* C:创建对象* D:启动线程* * 如何获取线程对象的名称呢?* public final String getName():获取线程名称* 如何设置线程对象的名称呢?* public final void setName(String name):设置线程名称* 针对不是Thread类的子类如何获取线程对象名称?* public static Thread CurrentThread():获取当前线程* */
public class ThreadDemo {public static void main(String[] args) {// TODO Auto-generated method stub//创建线程对象//MyThread my = new MyThread();//启动线程//my.run();//my.run();//调用run()方法,为什么是单线程呢?//因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的就是单线程的效果//要想看到多线程的效果,就必须述说另一个方法:start()//面试题:run()和start()的区别?//run():仅仅是封装被线程执行的代码,直接调用的是普通方法//start():首先启动了线程,然后再由jvm去调用该线程的run()方法
// MyThread my = new MyThread();
// my.start();
// //IllegalThreadStateException:非法线程状态异常
// //为什么呢?因为这个相当于是my线程被调用了两次,而不是两个线程启动。
// my.start();//创建两个线程对象//无参构造+setXxx()MyThread my1 = new MyThread();MyThread my2 = new MyThread();my1.setName("林青霞");my2.setName("刘毅");my1.start();my2.start();//带参构造方法给线程命名MyThread my1 = new MyThread("林青霞");MyThread my2 = new MyThread("刘毅");my1.start();my2.start();//我要获取main方法所在线程对象的名称,该怎么办?//遇到这种情况Thread类提供了一个很好玩的方法//public static Thread currentThread():返回当前正在执行线程对象//System.out.println(Thread.currentThread().getName());//main }
}
方式2:实现Runnable接口
A:自定义类MyRunnable实现Runnable接口
B:在MyRunnable里面重写run()
C:创建MyRunnable类的对象
D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
问题:
有了方式1,为什么还来一个方式2呢?
A:可以避免由于Java单继承带来的局限性
B:适合多个相同程序的代码区处理同一个资源的情况,把线程同程序的代码,数据有效分离
较好的体现了面向对象的设计思想。
代码示例:
package day23_Runable;
/** 实现类* */
public class MyRunable implements Runnable {@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<100;i++){//由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用System.out.println(Thread.currentThread().getName()+":"+i);}}}
package day23_Runable;
/** 测试类:* 创建线程:* 方式2:实现Runable接口的类,* * 步骤:* A:自定义类的MyRunable实现Runable接口* B:重写run()方法* C:创建MyRunable类的对象* D:创建Thread类的对象,并把C步骤的对象作为构造参数传递* */
public class MyRunableDemo {public static void main(String[] args) {//创建MyRunable对象MyRunable mr = new MyRunable();//创建Thread类的对象,并把C步骤的对象作为构造参数传递
// Thread th1 = new Thread(mr);
// Thread th2 = new Thread(mr);
// th1.setName("林青霞");
// th2.setName("刘毅");Thread th1 = new Thread(mr,"林青霞");Thread th2 = new Thread(mr,"刘毅");th1.start();th2.start();}
}
A:继承Thread类的实现
B:实现Runnable接口
A:为了更符合真是的场景,加入了休眠100毫秒
B:卖票问题a:同票多次b:负数票
最终版代码:
package day23_Runable;
/** 测试类:* 创建线程:* 方式2:实现Runable接口的类,* * 步骤:* A:自定义类的MyRunable实现Runable接口* B:重写run()方法* C:创建MyRunable类的对象* D:创建Thread类的对象,并把C步骤的对象作为构造参数传递* */
public class MyRunableDemo {public static void main(String[] args) {//创建MyRunable对象MyRunable mr = new MyRunable();//创建Thread类的对象,并把C步骤的对象作为构造参数传递
// Thread th1 = new Thread(mr);
// Thread th2 = new Thread(mr);
// th1.setName("林青霞");
// th2.setName("刘毅");Thread th1 = new Thread(mr,"林青霞");Thread th2 = new Thread(mr,"刘毅");th1.start();th2.start();}
}
package day23_SellTicketDemo_Ultimate2;
/** * 需求:某电影院正在上映贺岁档,共有100张票,而它有3个售票窗口* 请设计一个程序模拟该电影院售票* 用Runnable接口的方式实现* * 通过加入延迟(Thread.Sleep(100))后,就产生了两个问题:* A:相同的票卖了多次* CPU的一次操作必须是原子性的* B:出现了负数票* 随机性和延迟导致的* * 如何解决上述问题呢?* * 要解决问题,就要知道哪些原因会导致出现问题:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)* A:是否是多线程环境* B:是否有共享数据* C:是否有多条语句操作共享数据* * 我们来回想一下我们的程序是有没有上面的问题?* A:是否是多线程环境 是* B:是否有共享数据 是* C:是否有多条语句操作共享数据 是* * 由此可见我们的程序出现问题是正常的,因为它满足出现问题的条件。* 接下来才是我们要想想如何解决问题?* A和B的问题我们改变不了,我们只能想办法去把C改变一下* 思想:* 把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。* 问题是我们不知道怎么包?其实我也不知道,但是Java提供了:同步机制* * * 同步代码块:* 格式:synchronized(对象){* 需要同步的代码;* }* A:对象是什么呢?* 我们可以随便创建一个对象试试* B:需要同步的代码是哪些?* 把多条语句操作共享数据的代码部分给包起来* 注意:不同可以解决安全问题的根本原因就在那个对象上,该对象如同锁的功能。* 多个线程必须是同一把锁* * * 举例:* 火车上厕所* * 同步的特点:* 前提:* 多个线程* 解决问题时候需注意的:* 多个线程使用的是同一个锁对象* 不同的好处* 同步的出现解决了多线程的安全性问题* 不同的弊端* 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗资源,无形中会降低程序的运行效率。* * A:同步代码块的对象:* 任意对象* B:同步方法的格式及锁对象问题?* 把同步关键字加在方法上* //synchronized public void sellTicket(){}* 同步方法是谁呢?* this* C:静态方法及锁对象问题?* 静态方法的锁对象是谁呢?* 类的字节码文件对象(反射会讲的)* */
public class SellTicketDemo {public static void main(String[] args) {// TODO Auto-generated method stub//创建资源对象SellTicket st = new SellTicket();//创建三个线程对象Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");//启动线程t1.start();t2.start();t3.start();}}
A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
A:同步代码块synchronized(对象){需要被同步的代码;}注意:这里的锁对象可以是任意对象
B:同步方法把同步sychronized加在方法上这里的锁对象是this
C:不同静态方法把同步加在方法上这里的锁对象是当前类的字节码文件对象(.class)
1:public final boolean setDaemon(boolean on):设置该线程为守护线程或用户线程代码示例:
package day23_Thread;public class ThreadDaemon extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<100;i++){System.out.println(getName()+":"+i);Thread.yield();}}
}
package day23_Thread;
/** public final boolean setDaemon(boolean on):设置该线程为守护线程或用户线程* 当正在运行的线程都是守护线程时,Java虚拟机退出,该方法必须在启动线程前调用。* * */
public class ThreadDaemonDemo {public static void main(String[] args) {ThreadDaemon td1 = new ThreadDaemon();ThreadDaemon td2 = new ThreadDaemon();td1.setName("关羽");td2.setName("张飞");//设置守护线程td1.setDaemon(true);td2.setDaemon(true);td1.start();td2.start();Thread.currentThread().setName("刘备");for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+":"+i);}}
}
2:public final void join():等待该线程终止
package day23_Thread;public class ThreadJoin extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<100;i++){System.out.println(getName()+":"+i);}}
}
package day23_Thread;
/** public final void join():等待该线程终止* * */
public class ThreadJoinDemo {public static void main(String[] args) {// TODO Auto-generated method stubThreadJoin tj1 = new ThreadJoin();ThreadJoin tj2 = new ThreadJoin();ThreadJoin tj3 = new ThreadJoin();tj1.setName("李渊");tj2.setName("李世民");tj3.setName("李元霸");tj1.start();try {tj1.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}tj2.start();tj3.start();}}
3:public final int getPriority():返回线程对象的优先级public final void setPriority(int newPriority):更改线程的优先级
package day23_Thread;public class ThreadPriority extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<100;i++){System.out.println(getName()+":"+i);}}
}
package day23_Thread;
/**我们的线程没有设置优先级,肯定有默认优先级。*那么,默认优先级是多少呢?*如何获取线程对象的优先级? * public final int getPriority():返回线程对象的优先级*如何设置线程对象的优先级呢?* public final void setPriority(int newPriority):更改线程的优先级* *注意:* 线程默认的优先级是5* 线程优先级的范围是:1-10* 线程优先级高仅仅表示线程获取CPU的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果***IllegalArgumentException:非法参数异常*抛出的异常表明向方法传递了一个不合法或不正确的参数* */
public class ThreadPriorityDemo {public static void main(String[] args) {// TODO Auto-generated method stubThreadPriority tp1 = new ThreadPriority();ThreadPriority tp2 = new ThreadPriority();ThreadPriority tp3 = new ThreadPriority();tp1.setName("东方不败");tp2.setName("岳不群");tp3.setName("林平之");//获取默认优先级
// System.out.Priority());
// System.out.Priority());
// System.out.Priority());//设置线程的优先级//tp1.setPriority(1000);//IllegalArgumentException//设置正确的优先级tp1.setPriority(10);tp2.setPriority(1);tp1.start();tp2.start();tp3.start();}}
4:public static void Sleep(long millions)throws InterruptedException:睡眠线程
package day23_Thread;
/** public static void Sleep(long millions)throws InterruptedException* */
import java.util.Date;public class ThreadSleep extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<100;i++){ System.out.println(getName()+":"+i+",日期"+new Date());//睡眠//困了,我稍微休息1分钟try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}
package day23_Thread;public class ThreadSleepDemo {public static void main(String[] args) {// TODO Auto-generated method stubThreadSleep tp1 = new ThreadSleep();ThreadSleep tp2 = new ThreadSleep();ThreadSleep tp3 = new ThreadSleep();tp1.setName("林青霞");tp2.setName("林志强");tp3.setName("林志玲");tp1.start();tp2.start();tp3.start();}}
5:public final void interrupt():中断线程
package day23_Thread;import java.util.Date;/** 线程终止(Stop已过时,用Interrupt)* */
public class ThreadStop extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("开始执行"+new Date());//我要休息10秒,亲,不要吵醒我try {Thread.sleep(10000);} catch (InterruptedException e) {// TODO Auto-generated catch block//e.printStackTrace();System.out.println("线程终止了");}System.out.println("结束执行"+new Date());}
}
package day23_Thread;
/** public final void stop():让线程停止,过时了,但是还可以使用(不建议使用,不安全性)* public final void interrupt():中断线程* * */
public class ThreadStopDemo {public static void main(String[] args) {// TODO Auto-generated method stub//创建线程ThreadStop ts1 = new ThreadStop();ts1.start();//超过三秒就停止try {Thread.sleep(3000);//ts1.stop();//过时显示一条杠,后面代码都会停止,不再运行ts1.interrupt();//ThreadStop中catch后面的代码都会运行} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
6:public static void Tield():线程礼让
package day23_Thread;public class ThreadYield extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<100;i++){System.out.println(getName()+":"+i);Thread.yield();}}
}
package day23_Thread;
/** public static void Tield():线程礼让* 让多个线程的执行更和谐,但是不能保证一人一次* */
public class ThreadYieldDemo {public static void main(String[] args) {// TODO Auto-generated method stubThreadYield ty1 = new ThreadYield();ThreadYield ty2 = new ThreadYield();ty1.setName("林青霞");ty2.setName("刘毅");ty1.start();ty2.start();}}
A:StringBuffered
B:Vector
C:Hashtable
D:如何把一个线程不安全的集合类变成一个安全的集合类用Collections工具类的方法即可。//不安全 List<String> list1=new ArrayList<String>();//线程安全List<String> list2=Collections.synchronizedList(new ArrayList<String>());
本文发布于:2024-01-30 02:34:17,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170655326118619.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |