Java线程基础

说线程之前,先说说进程

进程

一、什么是进程
进程是系统进行资源分配和调用的独立单元,每一个进程都有它的独立内存空间和系统资源。

二、单进程操作系统和多进程操作系统的区别
a)多进程操作系统是指在同一个时段内可以执行多个任务(时间片)
b)边听音乐边敲代码,CPU切换非常快
c)Windows操作系统-多进程操作系统
d)Dos操作系统-单进程的操作系统
e)Linux操作系统-多用户多进程的操作系统

思考:现在的多核CPU是否可以让系统在同一个时刻可以执行多个任务吗?
理论上可以,但实际上还是同一时刻只能执行一个任务。

线程

三、什么是线程,理解线程和进程的关系
线程是进程里面的一条执行路径,每个线程同享进程里面的内存空间和系统资源
多线程在进程中会互抢资源(抢占资源具有随机性)

四、编写多线程的应用程序?

创建线程方式1: 创建一个类,继承Thread

说明:线程资源存放在寄存器区;(五大区域)

案例: 主线程和子线程各打印200次---互抢资源

创建线程方式1: 创建一个类,继承Thread

 */

class MyThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<10;i++){
			System.out.println("子线程"+i);
		}
	}
}

public class ThreadTest {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		myThread.start();//启动线程:将线程对象放入线程组,供cpu调度,cpu调度到你,则执行该对象的run方法
		//thread.start();   //能否创建线程对象,启动多次?   不行
		
		new MyThread().start();  //能否创建多个线程对象,启动多次?  不会, 每个对象的线程状态属性都初始为0
		
		for(int i=0;i<10;i++){
			System.out.println("主线程"+i);
		}
	}
}

创建线程方式2:实现runnable接口

class Task implements Runnable{

	@Override
	public void run() {
		for(int i=0;i<200;i++){
			System.out.println("子线程:"+i);
		}
	}
	
}

public class RunnableTest {
	public static void main(String[] args) {
		//new Thread(new Task()).start(); //接口实现多态方式
		//thread.start();
		
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=0;i<10;i++)
					System.out.println("子线程"+i);
			}
		}).start();
		
		for(int i=0;i<10;i++)
			System.out.println("主线程"+i);
	}
}

两种实现方式之间的区别:
第一种方式每个线程对象都有一份成员属性
第二种方式所以线程对象共用一份成员属性

经典面试题:请问当我们编写一个单纯的main方法时,此时该程序是否为多线程的?为什么?
是多线程的,至少有一个垃圾回收线程(守护线程)。

五、线程的优先级
注:改变线程的优先级,只是修改执行线程的概率而已,线程执行还是随机的。

/**
 * 如何给线程取名?
 * 1.带参构造,调成员属性接受姓名
 * 2.带参构造,调父类带参构造:super(name)
 * 3.带参构造,调Thread.currentThread().getName()方法获取名字
 *
 *练习:在主线程中创建两个以上的子线程,并且设置不同优先级,观察其优先级对线程执行结果的影响。
 */
class MyThread extends Thread{
	//private String name;
	/*public MyThread(String name) {
		super(name);
	}*/
	
	@Override
	public void run() {
		for(int i=0;i<20;i++)
			//System.out.println(super.getName()+"子线程"+i);
			System.out.println(Thread.currentThread().getName()+"子线程"+i);
	}
}

public class Test {
	public static void main(String[] args) {
		MyThread myThreadA = new MyThread();
		myThreadA.setName("a");
		myThreadA.setPriority(Thread.MIN_PRIORITY);//设置最大优先级
		myThreadA.start();
		
		MyThread myThreadB = new MyThread();
		myThreadB.setPriority(Thread.MAX_PRIORITY);
		myThreadB.start();
	}
}

六、让线程休眠 sleep

/**
	练习:编写一个抽取学员回答问题的程序,要求倒数三秒后输出被抽中的学员姓名
	i.采用数组存储6个学员姓名 
	ii.生成0-5之间的随机数,确定被抽中的学员
	iii.在屏幕每隔一秒,依次输出3,2,1,然后输出学员姓名
 */
    import java.util.Random;
    
    public class SleepTest {
    	public static void main(String[] args) throws InterruptedException {
    		String[] a = {"zz","xx","cc","dd","ee","ff"};
    		for(int i=3;i>=1;i--){
    			System.out.println(i);
    			Thread.sleep(1000);
    		}
    		int index = new Random().nextInt(a.length);
    		System.out.println(a[index]);
    	}
    }

七、线程的礼让 yield
执行后会发现,B线程礼让A线程(B线程抢到资源后,放弃资源,再次和A线程争抢资源),但是A线程还是抢不过B线程。

/**
 * 线程的礼让:礼让的线程抢到资源后,停止该次线程执行,继续开始争抢
 *  
 *从概念分析:礼让的线程会执行的慢些,但不是绝对性的
 *
 *练习:创建两个线程A,B,分别各打印100次,从1开始每次增加1,其中B一个线程,每打印一次,就yield一次,观察实验结果
 */
class ThreadA extends Thread{
	@Override
	public void run() {
		for(int i=0;i<10;i++){
			System.out.println("A"+i);
		}
	}
	
}
class ThreadB extends Thread{
	@Override
	public void run() {
		for(int i=0;i<10;i++){
			System.out.println("B"+i);
			ThreadB.yield();
		}
	}
	
}
public class Test {
	public static void main(String[] args) {
		new ThreadB().start();
		new ThreadA().start();
	}
}

八、线程的合并 join

/**
 * 合并(插队) 主线程和子线程同时运行,满足一定条件后,让子线程先运行至结束
 *
 *练习:主线程和子线程各打印200次,从1开始每次增加1,当主线程打印到10之后,让子线程先打印完再打印主线程
 */
class MyThread extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 10; i++)
			System.out.println("子线程2:" + i);

	}
}

public class Test1 {
	public static void main(String[] args) throws InterruptedException {
		MyThread myThread = new MyThread();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					System.out.println("线程1:" + i);
					if (i == 5) {
						try {
							myThread.join();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}//子线程插主线程的队
					}
				}
			}
		}).start();
		myThread.start();
	}
}

九、线程的中断

/**
 *2.设置开关变量进行中断应用
 *
 *案例:一个一直执行死循环的子线程,三秒后调用中断函数
 *
 */
class MyThreadA extends Thread{
	private boolean isbreak;	//设置是否中断的开关
	
	@Override
	public void run() {
		while(!isbreak){
			System.out.println("一直执行的子线程");
		}
	}

	public void setBreak(boolean b) {
		this.isbreak = b;
	}
}
public class Test2 {
	public static void main(String[] args) throws InterruptedException {
		MyThreadA myThreadA = new MyThreadA();
		myThreadA.setBreak(false);
		myThreadA.start();
		Thread.sleep(3000);
		myThreadA.setBreak(true);
	}
}

十、守护线程
Java的线程分为两种:User Thread(用户线程)、DaemonThread(守护线程)。
只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作,Daemon作用是为其他线程提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),他就是一个很称职的守护者。
User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。

/**
 * 守护线程:默默为用户线程服务的,只要用户线程还存在,则守护线程也存在;
 * 							只要用户线程都关闭了,则守护线程自动关闭
 * 
 * 典型的守护线程---jvm中的垃圾回收器
 *
 */

class MyThread extends Thread{
	@Override
	public void run() {
		while(true){
			System.out.println("一直执行的子线程");
		}
	}
}
public class Test {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		myThread.setDaemon(true); 	//设置为守护线程
		myThread.start();
		
		for(int i=0;i<100;i++){
			System.out.println("主线程。。。。");
		}
	}
}

十一、经典面试题:线程的生命周期
在这里插入图片描述
a)新建状态
i.在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时,它已经有了相应的内存空间和其它资源,但还处于不可运行状态。新建一个线程对象可采用线程构造方法来实现。
ii.例如:Thread thread=new Thread();
b)就绪状态
i.新建线程对象后,调用该线程的start()方法就可以启动线程。当线程启动时,线程进入就绪状态。此时,线程将进入线程队列排队,等待CPU调用,这表明它已经具备了运行条件。
c)运行状态
i.当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的run()方法。run()方法定义了该线程的操作和功能。
d)阻塞状态
i.一个正在执行的线程在某些特殊情况下,如被人为挂起,将让出CPU并暂时中止自己的执行,进入阻塞状态。在可执行状态下,如果调用sleep(2000)、wait()等方法,线程都将进入阻塞状态。阻塞时,线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。
e)死亡状态
i.线程调用stop()方法时或run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值