进程、线程、多线程、守护线程

TCP通信,多线程基础

什么是进程

-进程是操作系统中运行的一个任务(一个应用程序运行在一个进程中)。

-进程是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。

什么线程

-进程中包含的一个或多个执行单元称为线程(thread)。进程还拥有一个私有的虚拟地址空间,该空间仅能被它说包含的线程访问。

-线程只能归属于一个进程并且它只能访问该进程所拥有的资源。当操作系统创建一个进程后,该进程会自动申请一个名为主线程或首要线程的线程

线程的使用场合

-线程通常用于在一个程序中需要同时完成多个任务的情况。我们可以将每个任务定义为一个线程,使他们得以一同工作。

-也可以用于在单一线程中可以完成,但是使用多线程可以更快的情况。比如下载文件

并发原理

多个线程“同时”运行。这只是感官上的表现,其实是多个线程时,每个线程做一点,走走停停,不是绝对意义上的“同时发生”。

在这里插入图片描述

多线程

多线程改变了代码的执行方式,从原有的所有代码都是串行操作改变为多个代码片段之间并行操作。因此多线程运行多个代码片段“同时运行”。

多线程的两种创建方式:
第一种:

继承线程(Thread 不是抽象类可以实例化)并重写run方法,在run方法中定义线程要执行的任务

public class Thread{
    public static void main(String[] args){
        Thread t = new MyThread();
        t.start();
    }
}
class Mythread extends Thread{
    public void run(){     
        //运行代码
    }
}

启动线程时调用线程的start方法,而不是直接调用run方法。当线程的start方法调用后,线程纳入到线程调度中,当其第一次分配到时间片开始运行时,它的run方法会自动被执行

第一种创建线程的方式0:

优点:创建简单方便。

缺点:1、由于java是单继承的,这导致继承了线程就无法在继承其他的类,这会导致无法重用其他超类的方法而产生继承冲突问题

​ 2、定义线程的同时重写run方法,这就等于规定了线程要执行的具体任务,导致线程与其他执行的任务产生必然的耦合关系,不利于线程的重用

第二种:

实现Runnable接口,并重写run方法来单独定义线程的任务

public class Thread{
    public static void main(String[] args){
       //单独实例化
        Runnable r = new MyRunnable();
        r.start();
       //创建线程
        Thread t = new Thread(r);
        t.start();
    }
}
class MyRunnable implements Runnable{
    public void run(){
    }
}

优点:接口可以实现多个

使用匿名内部类的创建线程
public class Thread{
    public static void main(String[] args){
    //第一种:
        Thread t1 = new Thread(){
           public void run(){
           } 
        };
    //第二种:
        Runnable r = new Runnable(){
             public void run(){
           } 
        };
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
    }
}
获取主线程的方法
获取主线程currentThread()

线程提供的一个静态方法,该方法可以获取运行这个方法的线程

实际上,java的所有代码都是靠线程运行的,main方法也不例外。运行main方法的线程不是由我们创建的,而是JVM自行创建,并用来运行main方法。我们通常称这个线程为“主线程”

    Thread main = Thread.cuurrentThread();
    System.out.println("运行main方法的线程是:"+main);
获取线程的名字getName()
String name = main.getName();
获取唯一标识getId()
long id = main.getId();
获取线程的优先级getPriority()
int priority = main.getPriority(); 
判断线程是否活着isAlive()
boolean isAlive = main.isAlive();
判断是否是守护线程isDaemon()
boolean isDaemon = main.isDaemon();

判断线程是中断了inInterrupted()
boolean inInterrupted = main.inInterrupted();

线程的优先级

线程启动后就纳入到了线程调度中统一管理,什么时候获取CPU时间片完全取决于线程调度,线程是不能主动索取的,通过调整线程的优先级,可以最大程度的干涉分配CPU时间片的几率。

理论上线程优先级越高的线程获取CPU时间片的几率越高

线程的优先级有10个等级,用整数1-10表示,1是最小,5是默认,10是最高

Sleep()方法

线程提供的一个静态方法,该方法可以让运行这个方法的线程处于阻塞状态指定的毫秒,超过后线程会自动回到Runnable状态再次并发运行

eg:

public class SleepThread{
    public static void main(String[] args){
   		System.out.println("程序开始了");
        try{
			Thread.sleep(5000);//程序沉睡5000毫秒
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("程序结束了");
    }
}

sleep方法要求处理中断异常

interrupt()方法

当一个线程调用sleep方法处于阻塞状态的过程中,此时被其他线程调用了该线程的interrupt方法,那么就会打断这个线程的睡眠阻塞,测试sleep方法就会抛出中断异常告知

public class SleepDemo2 {
	public static void main(String[] args) {
		Thread huang = new Thread(){
			public void run(){
				System.out.println("煌:刚做完作业,睡一会");
				try {
					Thread.sleep(10000);					
				} catch (InterruptedException e) {
					System.out.println("煌:干嘛呢,干嘛了");
				}
				System.out.println("徐:醒了");
			}
		};				
		Thread xu = new Thread(){
			public void run(){
				System.out.println("徐:开始做作业");
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {					
				}
				System.out.println("哐当");
				System.out.println("徐:李总,搞定!");
				//中断huang的阻塞状态
				huang.interrupt();
			}
		};		
		huang.start();
		xu.start();
	}
}

守护线程setDaemon()

守护线程也称为后台线程,创建和使用上与前台线程一样,但有一点不同:

当进程结束时,所有正在运行的守护线程都会被强制停止

进程的结束:当所有普通线程都结束时,进程结束。

进程里面至少要有一条普通线程,如果一天普通线程都没有,进程将会结束

//设置为守护线程要在线程启动之前调用setDaemon方法
t.setDaemon(true);
t.start();

一定要在线程启动之前调用

main方法执行完,程序不一定结束,程序结不结束取决于进程结不结束。进程结不结束取决于普通线程是否结束。

阻塞join()方法

join方法允许当前线程在join方法所属线程上等待,直到该线程结束后,结束join阻塞继续后续操作。

所以 join 方法可以协调线程的同步运行。

同步运行:多个线程之间执行有顺序。

异步运行:多个线程之间各自执行各自的。

public class JoinDemo {
 private static boolean isFinish = false;	
 	public static void main(String[] args) {
		/*
		 * 当一个方法的局部内部类中引用了这个方法的其他局部变量时,该变量必须声明为final的
		 * JDK8之后可以不写final,但是该变量依然会被编译器最终改为final的,这是源自JVM的内存分配问题
		 */
		Thread download = new Thread(){
			public void run(){
				System.out.println("down:开始下载图片");
				for(int i =1;i<=100;i++){
					System.out.println("down:"+i+"%");
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {						
					}
				}
				System.out.println("down:图片下载完毕!");
				isFinish = true;
			}
		};		
		Thread show = new Thread(){
			public void run(){
				try {
					System.out.println("show:开始显示文字");
					Thread.sleep(3000);
					System.out.println("show:文字显示完毕!");			
					System.out.println("show:开始显示图片");
					/*
					 * 先等待download线程执行完毕(图片下载完)之后再继续后续工作
					 */
					download.join();
					if(!isFinish){
						throw new RuntimeException("图片加载失败!");
					}
					System.out.println("show:显示图片完毕!");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};		
		download.start();		
		show.start();
	}
}

sleep()方法的阻塞需要规定时间,而join方法会等待某个线程执行完后再执行后面的代码.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值