线程与多线程
什么是进程
进程是系统进行资源分配和调用的独立单元,每一个进程都有它的独立内存空间和系统资源。
什么是线程,理解线程和进程的关系
什么是线程?
线程是进程里面的一条执行路径,每个线程同享进程里面的内存空间和系统资源
一个进程 可以有 多个线程:各个线程都有不同的分工
理解线程和进程的关系
进程 与 进程 之间的关系:进程之间的内存空间和系统资源是独立的
同一个进程里的多条线程 :线程之间的内存空间和系统资源是共享的
进程里:可以有一条或一条以上的线程
进程里只有一条线程的情况下,这条线程就叫做主线程
进程里有多条线程的情况下,只有一条线程叫做主线程
Ps:线程是在进程里的,他们是包含关系
创建线程:
1.继承Thread类
编写步骤:写一个类继承Thread,重写父类的run()方法,在测试类的main方法中创建线程类对象,启动线程调用线程对象的start()方法
public class MyThread extends Thread{ //线程对象抢到CPU资源时,才会调用run方法 @Override public void run() { System.out.println("调用线程类的run方法"); } public static void main(String[] args) { //创建线程对象 MyThread t = new MyThread(); //启动线程 t.start(); }
2.实现Runnable接口
编写步骤:写一个类实现Runnable接口,重写接口的run方法,在测试类的main方法中创建接口的实现对象,创建一个Thread类的对象:Thread t = new Thread(接口的实现对象),调用start()方法启动线程
public class Task implements Runnable{ @Override public void run() { System.out.println("任务类的run方法"); } public static void main(String[] args) { //创建任务对象 Task task = new Task(); //创建线程对象 Thread t = new Thread(task); //启动线程 t.start(); }
多线程之间互相争抢资源的场景
需求:编写一个多线程的应用程序,
主线程打印1-100之间的数字,
子线程打印200-300之间的数字,
观察其输出的结果,体会多线程互相争抢资源的场景
public class MyThread extends Thread{ @Override public void run() { for (int i = 200; i <= 300; i++) { System.out.println("子线程:" + i); } } public static void main(String[] args) { //子线程 MyThread t = new MyThread(); t.start(); //主线程 for (int i = 1; i <= 100; i++) { System.out.println("主线程:" + i); } }
线程的优先级别
public final void setPriority(int newPriority) :改变线程的优先级
每个线程都有一定的优先级,优先级高的线程将获得较多的执行机会。每个线程默认的优先级都与创建它的父线程具有相同的优先级。Thread类提供了setPriority(int newPriority)和getPriority()方法类设置和获取线程的优先级,其中setPriority方法需要一个整数,并且范围在[1,10]之间,通常推荐设置Thread类的三个优先级常量:
MAX_PRIORITY(10):最高优先级
MIN _PRIORITY (1):最低优先级
NORM_PRIORITY (5):普通优先级,默认情况下main线程具有普通优先级。
线程取名字
public class MyThread extends Thread{ private String threadName; public MyThread(String threadName) { this.threadName = threadName; } @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println(threadName + ":" + i); } } //Thread.currentThread() -- 获取当前线程的名字 /* public class MyThread extends Thread{ public MyThread(String name) { super(name); } @Override public void run() { for (int i = 1; i <= 100; i++) { //System.out.println(super.getName() + ":" + i); //Thread.currentThread() -- 获取当前线程的名字 System.out.println(Thread.currentThread().getName() + ":" + i); } } */ public static void main(String[] args) { MyThread a = new MyThread("A"); MyThread b = new MyThread("B"); MyThread c = new MyThread("C"); //设置优先级别 a.setPriority(Thread.MAX_PRIORITY); b.setPriority(Thread.NORM_PRIORITY); c.setPriority(Thread.MIN_PRIORITY); a.start(); b.start(); c.start(); }
线程的休眠
使当前正public ==static== void sleep(long millis) :在执行的线程以指定的毫秒数暂停(暂时停止执行)。
* 需求:编写点名器,倒数3秒后输出姓名 public static void main(String[] args) throws InterruptedException { Random random = new Random(); String[] names = {"小红","小黄","小绿","小蓝"}; int index = random.nextInt(names.length); for (int i = 3; i>=1; i--) { System.out.println(i); //静态方法,会让当前线程休眠 Thread.sleep(1000); } System.out.println(names[index]); }
线程的礼让
public ==static== void yield():yield只是让当前线程暂停一下,让系统的线程调度器重新调度一次,希望优先级与当前线程相同或更高的其他线程能够获得执行机会,但是这个不能保证,完全有可能的情况是,当某个线程调用了yield方法暂停之后,线程调度器又将其调度出来重新执行。
线程的合并
void join() :等待该线程终止。
需求:主线程和子线程各打印200次,从1开始每次增加1,
当主线程打印到10之后,让子线程先打印完再打印主线程
public class MyThread extends Thread{ @Override public void run() { for (int i = 1; i <= 200; i++) { System.out.println("子线程:" + i); } } public static void main(String[] args) throws InterruptedException { MyThread t = new MyThread(); t.start(); for (int i = 1; i <= 200; i++) { System.out.println("主线程:" + i); if(i == 10){ //让子线程加入到主线程中 t.join(); } } }
线程的中断
public final void stop():强迫线程停止执行。 该方法具有固有的不安全性,已经标记为@Deprecated==(已过时、已废弃)==不建议再使用,那么我们就需要通过其他方式来停止线程了,其中一种方式是使用变量的值的变化来控制线程是否结束。
public void interrupt():中断线程。要通过这个方法制造InterrupttedException异常的话,前提是这个线程正在执行可能发生该异常的方法,例如:sleep,wait等。
public class MyThread extends Thread{ @Override public void run() { //Thread.currentThread().isInterrupted() - 判断当前线程是否消亡:false表示未消亡,true表示消亡 while(!Thread.currentThread().isInterrupted()){ System.out.println("aaa"); System.out.println("bbb"); System.out.println("ccc"); System.out.println("ddd"); } } * 注意:线程的run方法执行完毕,线程就消亡了 */ public static void main(String[] args) throws InterruptedException { MyThread t = new MyThread(); t.start(); Thread.sleep(3000); //改变线程状态:从未消亡状态改成消亡状态 false->true t.interrupt(); }
public class MyThread extends Thread{ private boolean bool = true; public void setBool(boolean bool) { this.bool = bool; } @Override public void run() { while(bool){ System.out.println("aaa"); System.out.println("bbb"); System.out.println("ccc"); System.out.println("ddd"); } } public static void main(String[] args) throws InterruptedException { MyThread t = new MyThread(); t.start(); Thread.sleep(3000); //中断线程 t.setBool(false); }
守护线程
public void setDaemon(true):将指定线程设置为守护线程。必须在线程启动之前设置,否则会报IllegalThreadStateException异常。
public class TestThreadMethod10 { public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我爱你"); } } }; // t.setDaemon(true);//把t线程变为守护线程 //如果没有把t线程变为守护线程,那么main线程自己的任务完成之后,依然会等待你,直到你执行完毕。因为这里是死循环,等价于main方法永远不会退出 t.start(); for(int i=1; i<=10; i++){ System.out.println("atguigu"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class TestThreadMethod11 { @Test public void test1(){ Thread t = new Thread(){ @Override public void run() { while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我爱你"); } } }; t.start(); //在test方法里面启动的线程,默认是守护线程 for(int i=1; i<=10; i++){ System.out.println("atguigu"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }