多线程
进程:
首先进程是由CPU,code,data三部分组成,它的缺点就是:内存的浪费,cpu的负担。
一个进程中的线程共享相同的内存单元/内存地址空间可以访问相同的变量和对象,而且它们从同一堆中分配对象,通信、数据交换、同步操作,这就使得通信更简便而且信息传递的速度也更快。
一个进程必须有一个进程:
进程抢占到CPU之后,线程再去抢占cpu资源,谁先抢到就执行谁。每次执行的顺序都不一样,比如用迅雷下载很多集电视剧的时候。
主线程:
Java虚拟机启动的时候会有一个进程java.exe,该进程中至少有一个线程,在负责java程序的执行。而且这个线程运行的代码存在于main方法中,该线程称之为主线程。
1.一个进程中的线程共享代码和数据空间
2.线程结束,进程未毕结束,但进程结束,线程一定结束。(就好比线程是学生,进程是班级,一个学生退学不代表整个班级都不存在了)
3.进程中包含线程,线程是进程的一部分
线程:
线程又被称为轻量级进程
多线程的优点
提高程序的运行效率。
线程和进程的区别:
进程:资源分配的单位
线程:执行和调度的单位
线程和进程二者的包含关系:
1. 没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个线程,则执行过程不是一条线的,而是多条线 (线程)共同完成的。
2.线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。
Java.lang.Thread 这个类
负责线程的功能
可以通过创建 Thread 的实例来创建新的线程。
可以通过创建 Thread 的实例来创建新的线程。
Thread thread = newThreadDome02();//父类引用指向子类对象,——需要和类名一致
thread.start();
每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。
每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("ThreadDome01..........");
}
public void run() {
// TODO Auto-generated method stub
System.out.println("ThreadDome01..........");
}
通过调用Thead类的start()方法来启动一个线程。
Thread thread = new ThreadDome02();
thread.start();
*
需要注意的是run();和start();的区分:
d.run();//仅仅是对象调方法,而是创建了线程但并没有运行
d.start();//开启线程并执行该线程的run方法
d.start();//开启线程并执行该线程的run方法
Thread类中的run方法是存储线程要运行的代码
主线程要运行的代码存放在main方法中
主线程要运行的代码存放在main方法中
继承Thread的步骤:
1.继承Thread类: public class ThreadDemo01 extends Thread {
2.重写run方法: public void run() {
for(int i=0;i<10;i++){
System.out.println("第"+i+"次threadrun........");
}
}
3.创建对象: ThreadDemo01 d=new ThreadDemo01();()
调用start()方法: d.start();
启动线程
实现Runable接口的步骤:
1.实现Runnable接口 ;
public class RunableDemo implements Runnable {
2.重写run方法
3.创建对象: RunableDemo rd=new RunableDemo();
2.重写run方法
3.创建对象: RunableDemo rd=new RunableDemo();
Thread t=new Thread(rd);
调用start()方法
启动线程
调用start()方法
启动线程
线程状态:
前面的就绪运行状态都顾名思义,那我就重点说一下阻塞和死亡先说一下阻塞
处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己运行,进入阻塞状态。
在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续执行。
在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续执行。
接下来说一下死亡状态:
线程死亡的原因有三个:
一个是正常运行的线程完成了它的全部工作;
另一个是线程被强制性地终止,如通过stop方法来终止一个线程【不推荐使用】;
三是线程抛出未捕获的异常。
接下来我想说一下线程的常用方法:
getPriority()
返回线程的优先级。
线程的优先级默认的是5,最高的优先级是10,最低的优先级是1.
可以通过线程的优先级在同等情况下改变程序的执行顺序,被优先执行,但在多线程的情况下结果不可预知,就好像
调用该方法的线程强制执行,其它线程处于阻塞状态,该线程执行完毕后,其它线程再执行
sleep(long millis)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
toString()
返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
yield()
暂停当前正在执行的线程对象,并执行其他线程。
public final void setPriority(String name)
设定线程名称
用同步(synchronized)解决线程的安全问题:
举个例子来说窗口在出售车票的时候,是不允许出现两个人同时在相同时间,同一列车的
一个车厢的同一座位的那么在程序中也有这样的需求,就需要用到synchronized同步代码块
但前提是:
(1)必须有两个或两个以上的线程
(2)必须是多个线程使用同一资源
(3)必须保证同步中只能有一个线程在运行
(2)必须是多个线程使用同一资源
(3)必须保证同步中只能有一个线程在运行
synchronized(obj){}中的obj称为同步监视器
执行过程如下:
第一个线程访问,锁定同步监视器,执行其中代码
第二个线程访问,发现同步监视器被锁定,无法访问
第一个线程访问完毕,解锁同步监视器
第二个线程访问,发现同步监视器未锁,锁定并访问
第二个线程访问,发现同步监视器被锁定,无法访问
第一个线程访问完毕,解锁同步监视器
第二个线程访问,发现同步监视器未锁,锁定并访问
将同步的代码块放到方法中
public synchronized void sale(){
//通常将当前对象作为同步对象
if (tick>0) {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"卖票:"+tick--);
}
}
//通常将当前对象作为同步对象
if (tick>0) {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"卖票:"+tick--);
}
}
Java提供了3个方法解决线程之间的通信问题