1.首先了解下什么是进程?
进程是指在操作系统中正在运行的一个应用程序,线程是指进程内独立执行某个任务的一个单元。
我们可以在任务管理器中打开:
2.什么是线程?
线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
多线程:解决多任务同时执行的需求,合理使用CPU资源。多线程的运行是根据CPU切换完成,如何切换由CPU决定,因此多线程运行具有不确定性。
3.线程和进程的区别?
一个进程是一个独立的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。
一个进程中的资源是该进程中的线程所共享的,但是有个顺序,得排队,等一个线程结束之后,下一个线程才能使用。互相争抢资源得,谁先抢到CPU谁就先运行。
4.实例
主线程---main,默认的线程。创建了多线程,需要运行的时候通过主线程来运行。
(默认情况下是单线程。)
Thread 类中的 start() 和 run() 方法有什么区别?
调用 start() 方法才会启动新线程;如果直接调用 Thread 的 run() 方法,它的行为就会和普通的方法一样;为了在新的线程中执行我们的代码,必须使用 Thread.start() 方法。
线程的run()方法是由java虚拟机直接调用的,如果我们没有启动线程(没有调用线程的start()方法)而是在应用代码中直接调用run()方法,那么这个线程的run()方法其实运行在当前线程(即run()方法的调用方所在的线程)之中,而不是运行在其自身的线程中,从而违背了创建线程的初衷;
创建多线程的方式:
(1)内部类分别继承Thread方法
(2)类实现Runnable接口
方法一:
(1)创建内部类,几个线程几个内部类
(2)线程的执行内容写在该内部类的run()方法中,类似于是线程的main方法
【下面有作业一、二用方法一实现】
方法二:
类实现Runnable抽象类,并实现run方法,将内容写在run方法中,在main中启动即可
方法二的弊端:不同线程之间只能做一个动作(因为只有一个run()方法)
方法二实例:
package aEightThirty;
public class OneTwoThree implements Runnable{
public void run() {
int i=0;
while(i<5){
System.out.println(Thread.currentThread().getName()+"---"+i);//获取当前线程的名字
i++;
}
}
public static void main(String [] args){
OneTwoThree twt = new OneTwoThree();
Thread t1 = new Thread(twt);
Thread t2 = new Thread(twt);
Thread t3 = new Thread(twt);
t1.setName("one");//为线程对象设置名字
t2.setName("two");
t3.setName("three");
t1.setPriority(8);//为对象设置优先级
t2.setPriority(5);
t3.setPriority(2);
t1.start();
t2.start();
t3.start();
}
}
设置优先级,0-10,优先级高的先执行
但执行效果如下,理由是现在电脑配置好,多核cpu,所以,要想实现效果,令只有一个cpu作用即可
任务管理器 ---> 详情信息 ---> eclipse ---> 右键 ---> 设置相关性 ---> 设置只有cpu0作用
作业一
记录做饼和吃饼的过程
1.tom每3秒做一张饼
2.jerry每5秒吃一张饼
3.一共做10饼
4.求tom做完的时间
5.求jerry吃完的时间
编写程序反应过程
package aEightThirty;
public class TomAndJerry {
int tomCount = 0; //记录tom做饼的个数
int jerryCount = 0; //记录jerry吃饼的个数
long tomTime = 0; //记录tom的时间差
long jerryTime = 0; //记录jerry的时间差
class Tom extends Thread { //tom的线程
public void run() {
long tomStart = System.currentTimeMillis(); //做饼之前获取当前系统时间
while (tomCount < 10) {
try {
sleep(3000); //睡3秒再执行
} catch (InterruptedException e) {
e.printStackTrace();
}
tomCount++;
System.out.println("tom在做第" + tomCount + "张饼");
}
tomTime = System.currentTimeMillis() - tomStart; //用执行十次后的当前时间 - 开始的时间 = 做饼时间差
System.out.println("tom做完的时间: " + tomTime);
}
}
class Jerry extends Thread { //jerry的线程
public void run() {
long jerryStart = System.currentTimeMillis();
while (jerryCount < 10) {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
jerryCount++;
System.out.println("jerry在吃第" + jerryCount + "张饼");
}
jerryTime = System.currentTimeMillis() - jerryStart;
System.out.println("jerry吃完的时间: " + jerryTime);
}
}
public void execute() {
Tom t = new Tom();
Jerry j = new Jerry();
t.start();
j.start();
}
public static void main(String[] args) {
TomAndJerry tj = new TomAndJerry();
tj.execute();
}
}
实现结果:
【注:设置当前时间那个只能用System.currentTimeMillis()而不能Thread.getTime(),第二个相减是零】
join函数:
//join礼让执行,对象.join()就是让别人礼让我这个对象
tom.start();
try {
tom.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
jerry.start();
执行效果就是tom十张饼都做完了,jerry 才开始吃
作业二 (出租车 和公交车 同时接人)(思考题)
编写程序反应 车站的运行状况
1.站内原有乘客 78人
2.出租车每4秒进站一次 接走乘客4人
3.公交车每16秒进站一次 接走乘客16人
4.每2秒又有一名新的乘客进站
问
当站内乘客第一次为0的时候
用了几辆出租车
用了几辆公交车
接走的客流量共多少人
时间是多少
package aEightThirty;
public class TaxiAndBus {
int count = 78; //存着站内的人数
int taxiCount = 0; //用了几辆出租车
int busCount = 0; //用了几辆公交车
int sum=0; //接走的客流量共多少人
long startTime = System.currentTimeMillis();//存放程序开始的时间
class Taxi extends Thread{
public void run(){
while(count!=0){ //车一次接走4个
try {
sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}zero();
//因为存在出租车载少于4大于0的情况
int num = (count-4)>0?4:count; //单次载的人数
count = (count-4)>0?count-=4:0;
taxiCount++;
sum+=num;
System.out.println("出租车接走乘客"+num+"人,剩余乘客"+count+"名");
}
}
}
class Bus extends Thread{
public void run(){
while(count!=0){ //车一次接走4个
try {
sleep(16000);
} catch (InterruptedException e) {
e.printStackTrace();
}zero();
int num = (count-16)>0?16:count;
count = (count-16)>0?count-=16:0;
busCount++;
sum+=num;
System.out.println("公交车接走乘客"+num+"人,剩余乘客"+count+"名");
}
}
}
class Passage extends Thread{
public void run(){
while(count!=0){ //车一次接走4个
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
zero();
count+=1;
System.out.println("一名新的乘客进站,剩余乘客"+count+"名");
}
}
}
public void execute(){
Taxi t = new Taxi();
Bus b = new Bus();
Passage p = new Passage();
t.start();
b.start();
p.start();
}
public void zero(){ //当站内人数为零时候
if(count == 0){
System.out.println("当站内乘客第一次为0的时候:");
System.out.println("用了"+taxiCount+"辆出租车");
System.out.println("用了"+busCount+"辆公交车");
System.out.println("接走的客流量共"+sum+"人");
System.out.println("时间是"+(System.currentTimeMillis() - startTime));
System.exit(0);
}
}
public static void main(String [] args){
TaxiAndBus tb = new TaxiAndBus();
tb.execute();
}
}
运行结果:
程序中存在同步的问题,所以同上,设置只有cpu0可以使用
也可以用sychronize来加锁