基本概念:
程序:为完成特定任务,用某种编程语言编写的一组指令的集合,一段静态的代码
进程:程序的一次执行过程或是正在运行的一个程序,是一个动态的过程
有他自身的产生、存在、消亡的过程
线程:进程可以进一步细化分为线程,是一个程序内部的一条执行路径
单核cpu和多核cpu
单核cpu,其实是一种假的多线程,因为在一个时间单元内们,也只能执行一个线程任务
如果是多核的话,才能更好地发挥多线程的效率
一个java程序java。exe;至少有三个线程
main()主线程
gc()垃圾回收线程
异常处理线程
并行:多个cpu同时执行多个任务,是指多个线程任务在不同CPU上同时进行,是真正意义上的同时执行
并发:一个cpu同时执行多个任务,是指多个线程任务在同一个CPU上快速地轮换执行,由于切换的速度非常快,
给人的感觉就是这些线程任务是在同时进行的,但其实并发只是一种逻辑上的同时进行
线程背景:
以单个cpu为例,只使用单个线程先后完成多个任务肯定比多线程来完成用的时间长
单线程:一个人烧10壶水,单线程就是一个接一个烧
多线程:一个人同时烧10壶水
多线程的优点:
1.提高 应用程序的响应
2.提高计算机系统cpu的利用率
3.改善程序结构,
何时需要多线程
1.程序需要同时执行两个或者多个任务
2.程序需要实现一些需要等待的任务时
3.需要一些后台运行的程序时
java中如何实现多线程
1.继承Thread,在java中用来表示线程的类,里面包含了一个线程运行过程的方法run()方法
(1)写一个类,继承Thread(注意:当继承之后,就不能继承其他类)
(2)重写run()方法
(3)创建线程实例、对象的start()方法启动线程
2.实现Runnable接口
(1)写一个类,实现Runnable接口
(2)重写run方法
(3)创建实例、对象
(4)调用Start
方式二:采用匿名内部类放射式创建线程(固定格式)
两种方式的区别:
实现Runnable接口比继承Thread类具有的优势
1.适合多个相同的程序代码的线程去处理同一个资源
2.可以避免java中单继承的限制
3.代码可以被多个线程共享
4.线程池只能放实现Runnable的类
线程的生命周期:
线程具有生命周期,其中包含5个状态
1.新建状态:就是线程被创建处于的状态,
在用户创建该线程实例后,调用之前线程都处于新建状态
2.就绪状态:当用户调用start方法后,线程处于就绪状态
表示可以执行但是不一定会立即执行,而等待cpu分配时间片进行处理
3.运行状态:当线程的到系统资源就进入运行状态,一旦线程进入运行状态
它就会在就绪与运行状态下转换,同时也有可能进入暂停和死亡状态
cpu为该线程分配时间片
4.暂停状态(休眠、等待、阻塞等):当运行状态下线程调用sleep()、wait()方法
或者发生阻塞时,就会进入暂停状态
比如接收键盘输入Scanner
当在休眠状态结束,调用notify()、notifyAll()方法或者阻塞接触时
就会重新进入就绪状态
5.死亡状态:当线程的run方法运行执行完毕时,或者线程发生错误、异常,线程就会进入死亡状态
注意:
1.线程创建,并不会马上执行,需调用start方法,使其处于就绪状态
2.线程处于就绪状态,也不会立即执行,需要等待cpu分配时间片
3.当线程阻塞时,会让出占有的cpu,当阻塞结束时,线程就会进入就绪状态,重新等待
cpu分配时间片,而不是直接进入运行状态
/
blic class ThreadDemo {
public static void main(String[] args) {
Thread a=new A();
a.start();
/*
* 1.启动线程调用start()方法
* 2.启动线程之后调用run()方法
* 3.需要线程完成某件事,将对应的代码放入到run()中即可
*/
Thread b=new B();
b.start();
Thread c=new Thread(new c());
c.start();
//本质上采用Thread类创建线程:匿名内部类
Thread d=new Thread() {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("159");
}
}
};
d.start();
}
ass A extends Thread{
public void run() {
for(int i=0;i<100;i++) {
System.out.println("123");
}
}
ass B extends Thread{
public void run() {
for(int i=0;i<100;i++) {
System.out.println("789");
}
}
ass c implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++) {
System.out.println("456");
}
}
*
* 操作线程的常用方法
* 1.Thread.sleep(毫秒数time)让线程休眠time毫秒数,该线程从运行状态进入到阻塞状态
* 不会与其他线程占用cpu
* 当毫秒数过后,该线程会从阻塞进入到就绪状态,重新与其他线程抢占cpu
*/
System.out.println("请输入你要倒计时的数字");
Scanner scan=new Scanner(System.in);
int num=scan.nextInt();
for(int i=num;num>-1;num--) {
System.out.println("实时数:");
System.out.println(num);
Thread.sleep(1000);
}
System.out.println("倒计时结束");
/*
* 2.中断interrupt()
*
*/
Thread mk=new Thread() {
public void run() {
System.out.println("hello");
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
System.out.println("world");
}
System.out.println("你好");
}
};
Thread th=new Thread() {
public void run() {
System.out.println("世界这么大");
for (int i = 0; i < 7; i++) {
System.out.println("我想去看看!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mk.interrupt();//中断,抛出中断异常
}
};
mk.start();
th.start();
/*
*3. 获取当前运行的线程currentThread()
*4.修改线程名setname(),获取当前线程名字getName()
*5.设置线程优先级setPriority
* 优先级1-10整数值
* 1.优先级最高10
* 2.线程默认优先级为5
* 3.优先级高,获得cpu的机会多,机会的多少不能通过代码干预
*6.yield()释放当前线程
*7.join()t2线程中调用t1的join(),此时的t2就进入了阻塞状态
* 直到t1执行完成后,线程t2才结束阻塞状态
* 用于协调线程执行"同步运行"
* 线程是并发运行的,感官上是各干各的,这种方式成为异步运行
* 实际上开发中,我们也需要让线程在特定的环节上有顺序的运行,这种操作叫做
* 同步运行
*/
Thread t=Thread.currentThread();
System.out.println(t);
t.getName();
t.setName("123");
t.setPriority(10);
System.out.println(t);
/ t.yield();//释放当前cpu执行权
}
/ public B(String name) {
/ super(name);//调用父类传String的构造方法,也可以修改线程名
/}