1.多线程概述
package com.java.javase.Thread;
public class chapterFirst {
多线程
* 1、什么是进程?什么是线程?
* 进程是一个应用程序(1个进程是一个软件)
* 线程是一个进程中的执行场景/执行单元
* 一个进程可以启动多个线程
*
* 2、对于java程序来说,当在DOS命令窗口中输入:
* java HelloWorld 回车之后会先启动JVM,而JVM就是一个进程
* JVM再启动一个主线程调用main方法
* 再启动一个垃圾回收线程负责看护,回收垃圾
* 最起码,现在的java程序中至少有两个线程并发,一个是垃圾回收线程,一个是执行main方法的主线程
*
* 3、进程和线程是什么关系?举个例子
* 阿里巴巴:进程
* 马云:阿里巴巴的一个线程
* 童文红:阿里巴巴的一个线程
*
* 京东:进程
* 强东:京东的一个线程
* 妹妹:京东的一个线程
*
* 进程可以看做是现实生活当中的公司
* 线程可以看做是公司当中的某个员工
*
* 注意:
* 进程A和进程B的内存独立不共享(阿里巴巴和京东的资源不会共享的!)
* 魔兽游戏是一个进程
* 酷狗音乐是一个进程
* 这两个进程是独立的,不共享资源
*
* 线程A和线程B呢?
* 在java语言中:
* 线程A和线程B,堆内存和方法区内存共享
* 但是栈内存独立,一个线程一个栈
*
* 假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,互不干扰,各自执行各自的,这就是多线程并发
*
* 火车站,可以看做是一个进程
* 火车站中的每一个售票窗口可以看做是一个线程
* 我在窗口1购票,你可以在窗口2购票,你不需要等我,我也不需要等你
* 所以多线程并发可以提高效率
*
* java中之所以有多线程机制,目的就是为了提高程序的处理效率
*
* 4、思考一个问题:
* 使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束?
* main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在压栈弹栈
*
* 5、分析一个问题:对于单核的CPU来说,真的可以做到真正的多线程并发吗?
* 对于多核的CPU电脑来说,真正的多线程并发是没问题的
* 4核CPU表示同一个时间点上,可以真正的有4个进程并发执行
*
* 什么是真正的多线程并发?
* t1线程执行t1的
* t2线程执行t2的
* t1不会影响t2,t2也不会影响t1————多线程并发
*
* 单核的CPU表示只有一个大脑:
* 不能够做到真正的多线程并发,但是可以做到给人一种“多线程并发”的感觉
* 对于单核的CPU来说,在某一个时间点上实际上只能处理一件事情,但是由于
* CPU的处理速度极快,多个线程之间频繁切换执行,给人来的感觉是:多个事情同时在做!!!!!
* 线程A:播放音乐
* 线程B:运行魔兽游戏
* 线程A和线程B频繁切换执行,人类会感觉音乐一直在播放,游戏一直在运行,给我们的感觉是同时并发的
*
* 电影院采用胶卷播放电影,一个胶卷一个胶卷播放速度达到一定程度之后,
* 人类的眼睛产生了错觉,感觉是动画的,这说明人类的反应速度很慢,就像
* 一根钢针扎到手上,到最终感觉到疼,这个过程是需要“很长的”时间的,在
* 这个期间计算机可以进行亿万次的循环,所以计算机的执行速度很快
*
* 6、java语言中,实现线程有两种方式,哪两种方式呢?
* java支持多线程机制,并且java已经将多线程实现了,我们只需要继承就行
* 第一种方式:编写一个类,直接继承java.lang.Thread,需要重写run方法
* // 定义线程类
* public class MyThread extends Thread{
* public void run(){
* }
* }
* // 创建线程对象
* MyThread t = new MyThread();
* // 启动线程
* t.start();
*
* 第二种方式:编写一个类,实现java.lang.Runnable接口,实现run方法
* // 定义一个可运行的类
* public class MyRunnable implements Runnable {
* public void run(){
* }
* }
* // 创建线程对象
* Thread t = new Thread(new MyRunnable());
* // 启动线程
* t.start();
* 注意:第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,更灵活
* 7、怎么获取当前线程对象?
* static Thread currentThread();
* 获取线程对象的名字
* String name=线程对象.getName();
* 修改线程对象的名字
* 线程对象.setName("线程名字");
*
* 8、关于线程对象的生命周期?
* 新建状态
* 就绪状态
* 运行状态
* 阻塞状态
* 死亡状态
* 9、了解——关于线程的调度
* 9.1、常见的线程调度模型有哪些?
* 抢占式调度模型:
* 那个线程的优先级比较高,抢到的CPU时间片的概率就高一些/多一些
* java采用的就是抢占式调度模型
* 均分式调度模型:
* 平均分配CPU时间片,每个线程占有的CPU时间片时间长度一样
* 平均分配,一切平等
* 有一些编程语言,线程调度模型采用的是这种方式
*
* 9.2、java中提供了哪些方法是和线程调度有关系的呢?
* 实例方法:
* void setPriority(int newPriority) 设置线程的优先级
* int getPriority() 获取线程优先级
* 最低优先级1
* 默认优先级是5
* 最高优先级10
* 优先级比较高的获取CPU时间片可能会多一些(但也不完全是,大概率是偏向优先级比较高的)
* 静态方法:
* static void yield() 让位方法,暂停当前正在执行的线程对象,并执行其他线程
* yield()方法不是阻塞方法,让当前线程让位,让给其它线程使用
* yield()方法的执行会让当前线程从“运行状态”回到“就绪状态”
* 注意:在回到就绪状态之后,有可能会再次抢到时间片
* 实例方法:
* void join()————合并线程
* class MyThread1 extends Thread {
* public void doSome(){
* MyThread2 t = new MyThread2();
* t.join(); // 当前线程进入阻塞,t线程执行,直到t线程结束,当前线程才可以继续,两个栈之间发生了等待关系
* }* }
* class MyThread2 extends Thread{
* }
*/
}
2.实现线程的第一种方式
主线程任务和分支线程任务演示
package com.java.javase.Thread;
public class ThreadTest01 {
public static void main(String[] args) {
MyThread myThread=new MyThread();
myThread.start();
for(int i=0;i<100;i++){
System.out.println("主线程任务——"+i);
}
}
}
class MyThread extends Thread{ // 继承Thread不能再继承别的类
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("分支线程任务——"+i);
}
}
}
运行结果:
主线程任务——0
分支线程任务——0
主线程任务——1
分支线程任务——1
分支线程任务——2
分支线程任务——3
分支线程任务——4
分支线程任务——5
分支线程任务——6
分支线程任务——7
分支线程任务——8
分支线程任务——9
分支线程任务——10
分支线程任务——11
分支线程任务——12
分支线程任务——13
分支线程任务——14
分支线程任务——15
分支线程任务——16
分支线程任务——17
分支线程任务——18
分支线程任务——19
主线程任务——2
分支线程任务——20
主线程任务——3
分支线程任务——21
主线程任务——4
3.实现线程的第二种方式
package com.java.javase.Thread;
public class ThreadTest02 {
public static void main(String[] args) {
Thread t=new Thread(new Myrunnable());
t.start();
for(int i=0;i<100;i++){
System.out.println("主线程——"+i);
}
}
}
class Myrunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("分支线程——"+i);
}
}
}
package com.java.javase.Thread;
// 采用匿名内部类编写
public class ThreadTest03 {
public static void main(String[] args) {
Thread t=new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("分支线程——"+i);
}
}
});
t.start();
for(int i=0;i<100;i++){
System.out.println("主线程——"+i);
}
}
}
4.关于线程对象的名字
package com.java.javase.Thread;
// 1.获取当前线程对象
// 2.获取线程对象的名字
// 3.修改线程对象的名字
public class ThreadTest04 {
public static void main(String[] args) {
Thread currentThread=Thread.currentThread();
// 获取主线程对象的名字
System.out.println(currentThread.getName());
MyThread t=new MyThread();
// 设置线程对象的名字
t.setName("tttt");
// 获取线程对象的名字
System.out.println(t.getName());
// 启动线程
t.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("分支线程任务——"+i);
}
}
}
5.获取当前线程
Thread currentThread=Thread.currentThread(); System.out.println(currentThread.getName());
6.线程的sleep方法
package com.java.javase.Thread;
// 关于线程的sleep方法
// static void sleep(long millis) 抛出中断异常 InterruptedException
// 参数是毫秒
// 作用:让当前线程陷入休眠,进入“阻塞状态”,放弃占有的CPU时间片,让给其他线程使用
// 间隔特定的时间去执行特定的代码,每隔多久执行一次
// 这行代码出现在A线程中,A线程就会进入休眠状态
// 这行代码出现在B线程中,B线程就会进入休眠状态
public class ThreadTest05 {
public static void main(String[] args) {
try{
Thread.sleep(1000*5);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("hello world!");
}
}
package com.java.javase.Thread;
public class ThreadTest06 {
public static void main(String[] args) {
Thread t=new myThread();
t.setName("java");
t.start();
try{
t.sleep(1000*5); // 在执行的时候还是会转换成Thread.sleep(1000*5);
}catch(InterruptedException e){ // 这行代码的作用是:让当前线程进入休眠,也就是说main线程进入休眠
e.printStackTrace(); // 这行代码出现在main方法中,main线程睡眠
}
System.out.println("hello world!"); // 5s之后输出
}
}
class myThread extends Thread{
public void run(){
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
7.中断线程的睡眠
package com.java.javase.Thread;
// 怎么叫醒一个正在睡眠的线程,中断线程的睡眠?
public class ThreadTest07 {
public static void main(String[] args) {
Thread t=new Thread(new MyRunnable());
t.start();
try{
Thread.sleep(1000*10);
}catch(InterruptedException e){
e.printStackTrace();
}
t.interrupt();
}
}
class MyRunnable implements Runnable{
// run()当中的异常不能throws,只能try catch
// 因为run()方法在父类中没有抛出任何异常,子类不能比父类抛出更多的异常
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"---begin");
try{
Thread.sleep(1000*60*60*24);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---over");
}
}
8.stop方法—强行终止线程,直接将线程杀死,容易丢失数据



