一阶段课堂笔记——多线程基础

1.进程与线程

1.1 进程

进程是指一个动态的过程,它指的是从代码加载到执行完毕的一个完成过程。

特点:

(1)独立性:不同进程之间是独立的,相互之间资源不共享

(2)动态性:进程是一直活动的

(3)并发性:多个进程可以在单个处理器上同时执行,而且互不影响

1.2 线程

线程是一条执行路径,是进程的组成部分,一个进程可以有多个线程,每个线程去处理一个特定的子任务。

特点:

线程的执行时抢占式的,多个线程在同一个进程中可以并发的执行(其实就是CPU快速的在不同线程之间切换)

1.3 进程和线程的区别

(1)一个程序运行后至少有一个进程,一个进程至少有一个线程,否则这个进程是没有意义的

(2)进程之间不能共享资源 (独立),线程之间是抢占式,谁抢到CPU谁先执行

(3)系统创建进程需要为该进程重新分配资源,而创建线程容易的多,因此使用线程实现多任务并发比多进程的效率高

2.多线程

2.1 继承Thread类

(例)四个窗口各卖100张票:

public class TicktWindow extends Thread{
	
	//票
	private int ticket=100;

	public TicktWindow(String name) {
        //Thread类中有name属性
		super(name);
	}
	//run实现卖票功能
	@Override
	public void run() {
		while(true) {
			if(ticket<1) {
				break;//结束循环
			}
			System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票");
			ticket--;
		}
	}
	
}

public class Demo {
	public static void main(String[] args) {
		TicktWindow w1=new TicktWindow("窗口1");
		TicktWindow w2=new TicktWindow("窗口2");
		TicktWindow w3=new TicktWindow("窗口3");
		TicktWindow w4=new TicktWindow("窗口4");
		//启动线程
		w1.start();
		w2.start();
		w3.start();
		w4.start();
	}
}

2.2 实现Runnable接口

(例)四个窗口一起卖100张票

public class Ticket implements Runnable{

	//票
	private int ticket=100;
	/**
	 * 卖票功能
	 */
	@Override
	public void run() {
		while(true) {
			if(ticket<1) {
				break;
			}
			System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");
			ticket--;
		}
		
	}

}

public class Demo2 {
	public static void main(String[] args) {
		//创建票对象
		Ticket ticket=new Ticket();
		//创建窗口
		Thread w1=new Thread(ticket, "窗口1");
		Thread w2=new Thread(ticket, "窗口2");
		Thread w3=new Thread(ticket, "窗口3");
		Thread w4=new Thread(ticket, "窗口4");
		//启动线程
		w1.start();
		w2.start();
		w3.start();
		w4.start();
	}
}

注意:这里会出现多线程同步问题(四个窗口都卖同一张票),原因是上一个线程还没执行完下一个线程就已经开始执行了

(例)男友朋友存钱取钱问题

同理:有可能输出结果是女朋友先取钱,实际上是男朋友线程存钱还没结束,女朋友线程就抢到CPU进来执行

而且也有可能是女朋友线程一直在取钱

2.3 两种方法实现方式的比较

(1)两中方式获取线程名字的方式:Thread.currentThread().getName

(2)继承Thread类的方式:没有资源共享,编写简单

弊端:已经继承了Thread类,不能再继承其他类

(3)实现Runnable接口的方式:适合多个线程共享同一个资源的情况;资源类实现Runnable接口(四个窗口一起卖票问题),如果资源类有多个操作,需要把功能提出来,单独实现Runnable接口(男女朋友存钱取钱问题)

2.4 使用Callable接口实现多线程

public class MyCallable implements Callable<Integer>{

	@Override
	public Integer call() throws Exception {
		int sum=0;
		for(int i=0;i<=100;i++) {
			sum+=i;
		}
		System.out.println(Thread.currentThread().getName()+"计算完毕");
		return sum;
	}

}

public class Demo {
	public static void main(String[] args) throws Exception {
		//1创建Callable对象
		MyCallable callable=new MyCallable();
		//2把Callable变成任务  (未来的任务)
		FutureTask<Integer> task=new FutureTask<>(callable);
		//3创建线程对象
		Thread thread=new Thread(task, "future1");
		//4执行
		thread.start();
		//5获取执行结果
		Integer sum=task.get();
		System.out.println(sum);
		
	}
}

3. 线程常用方法

3.1 设置获取线程的名称

设置:setName("xxx");

获取:super.getName();

Thread.currentThread().getName();

3.2 线程休眠(sleep)

public class SleepThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<20;i++) {
			System.out.println(Thread.currentThread().getName()+"....."+i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

public class Demo {
	public static void main(String[] args) {
		SleepThread sleepThread=new SleepThread();
		sleepThread.start();
	}
}

3.3 设置优先级(setPriority)

可以通过设置优先级来改变线程抢到时间片的概率,优先级高的线程获得较多的执行机会

默认情况下,每个线程都与创建他的父线程具有相同的优先级

优先级范围:1~10,默认为5,对应数值越大,说明优先级越高


public class PriorityThread extends Thread{
	
	public PriorityThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"----------------"+i);
		}
	}
}

public class Demo {
	public static void main(String[] args) {
		PriorityThread p1=new PriorityThread("线程1");
		PriorityThread p2=new PriorityThread("线程2");
		PriorityThread p3=new PriorityThread("线程3");
		//设置优先级
		p1.setPriority(1);
		p3.setPriority(10);
		
		//启动
		p1.start();
		p2.start();
		p3.start();
		
		
	}
}

3.4 合并(加入)线程(join)

在执行原来线程的过程中,如果遇到了合并线程,则优先执行合并进来的线程

public class JoinThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<50;i++) {
			System.out.println(Thread.currentThread().getName()+"------------"+i);
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

public class Demo {
	 public static void main(String[] args){
		JoinThread joinThread=new JoinThread();
		joinThread.start();
		//加入线程
		try {
			joinThread.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
        //阻塞当前线程(主线程),等到子线程执行完,才继续执行
		for(int i=0;i<20;i++) {
			System.out.println("主线程..........."+i);
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

3.5 后台线程(setDaemon)

线程分为前台(用户)线程和后台(守护)线程

后台线程:隐藏起来一直默默运行的线程,直到进程结束,又称守护线程(JVM的垃圾回收线程)

public class DaemonThread extends Thread{
	@Override
	public void run() {
		for (int i = 0; i < 50; i++) {
			System.out.println(Thread.currentThread().getName()+"---"+i);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}	


public class Demo {	
	public static void main(String[] args) throws Exception {
		DaemonThread daemonThread=new DaemonThread();
		//设置线程为后台线程
		daemonThread.setDaemon(true);
		daemonThread.start();
		for(int i=0;i<20;i++) {
			System.out.println("主线程............."+i);
			Thread.sleep(100);
		}
	}
}

3.6 线程让步(yield)

让正在执行的线程暂停,但它不会阻塞该线程,他只是将该线程转入就绪状态

实际上,当某个线程调用了yield方法暂停之后,只有优先级与它相同或比他高的线程才会获得执行的机会

public class YieldThread extends Thread{
	
	public YieldThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		for(int i=0;i<1000;i++) {
			System.out.println(Thread.currentThread().getName()+"=="+i);
			if(i==50) {
                Thread.yield();//暂停线程执行,让给其他优先级相同或高的线程执行
            }
		}
	}
}

public class Demo {	
	public static void main(String[] args) {
		YieldThread y1=new YieldThread("线程1");
		YieldThread y2=new YieldThread("线程2");
		
		y1.start();
		y2.start();
	}
}

3.7 线程中断()

程序在等待过程中,可以使用interrupt方法打断

public class InterruptThread extends Thread {
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+"开始执行了...");
		try {
			Thread.sleep(20000);
			System.out.println(Thread.currentThread().getName()+"自然醒了");
		} catch (InterruptedException e) {
			System.out.println(Thread.currentThread().getName()+"被打醒了...");
		}
		System.out.println(Thread.currentThread().getName()+"执行完毕...");
	}
	
	
}

public class Demo {
	public static void main(String[] args) throws Exception{
		InterruptThread interruptThread=new InterruptThread();
		interruptThread.start();
		System.out.println("20秒输入任意字符,结束子线程");
		System.in.read(); //会停止,等到键盘录入
		interruptThread.interrupt();//打断子线程
		System.out.println("主线程结束了");
	}
}

4. 线程的生命周期

    对于线程,当线程被创建,进入新生状态,调用start()方法 ,进入就绪状态(可执行状态),如果抢到cpu,进入运行状态,运行过程中出现了阻塞,进入阻塞状态,如果程序正常结束进入死亡状态。

五状态生命周期:

 

七状态生命周期

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值