/* 多线程 进程:进程就是正在进行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元 线程:线程是进程中的内容或者说是进程中的一个独立的控制单元,线程控制者进程的执行,每一个进程中至少都会有一个线程 Java虚拟机启动的时候会有一个进程java.exe该进程中至少有一个线程在负责java程序的执行,而且这个线程运行的代码 存在于main方法中 多线程存在的意义:提高了程序的运行效率 */ class ThreadMainDemo1 extends Thread //定义类继承Thread { public void run() //重写run方法 { for(int x=0; x<60; x++) System.out.println("demo run"); } } class ThreadDemo1 { public static void main(String[] args) { ThreadMainDemo1 d = new ThreadMainDemo1(); //创建好一个对象,就创建好一个线程 d.start(); //虚拟机调用run方法,这里叫开始运行线程了 for(int x=0; x<60; x++) System.out.println("hello world!"); } } /* 发现运行结果每次都不同 因为多个线程都在获取cpu的执行权,cpu执行到谁,谁就能运行。在某一个时刻,只能有一个 程序在运行(多核除外)cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象 的把多线程的运行行想象为在互相抢夺cpu的执行权这就是多线程的一个特性: 随机性,谁抢到谁执行,至于执行多长时间,cpu说了算 为什么要重写run方法呢? 因为如果不重写run方法,那么你线程就没有代码可执行 因为,start()函数调用run方法,但是如果你不重写run方法,那么run方法中就没有代码 可执行,所以必须要重写run方法 创建线程的方式一: 继承Thread类 1.子类覆盖父类中的run方法,将线程运行代码存放在run中 2.建立子类对象的同时线程也被创建 3.通过调用start方法开启线程 */ class ThreadMainDemo2 extends Thread { public void run() { for(int x=0; x<60; x++) System.out.println("demo run"); } } class ThreadDemo2 { public static void main(String[] args) { ThreadMainDemo2 d = new ThreadMainDemo2(); d.start(); //为什么不用d.run因为,只有start能开启线程,否则是主线程在调用run,就没意义 } } //练习:创建2个线程,和主线程交替运行 class ThreadMainTest1 extends Thread { private String name; ThreadMainTest1(String name) { this.name = name; } public void run() { for(int x=0; x<60; x++) { System.out.println(name +"ThreadMainTest run..." + x); } } } class ThreadTest1 { public static void main(String[] args) { ThreadMainTest1 t1 = new ThreadMainTest1("one"); ThreadMainTest1 t2 = new ThreadMainTest1("two"); t1.start(); t2.start(); //t1.run(); //如果是执行run打印结果必然是按顺序来的,先是one,然后two,然后才是主函数的代码 //t2.run(); //如果是执行run打印结果必然是按顺序来的,先是one,然后two,然后才是主函数的代码 for(int x=0; x<60; x++) { System.out.println("Main..." + x); } } } /* 线程的运行状态 start() //运行 stop() //销毁 sleep(time) //冻结 wait() //等待 notify() //唤醒 */ /* 获取线程对象以及名称 Thread.currentThread(); //获取当前线程对象 getName(); //获取线程名称 setName(); //设置线程名称,或构造函数 */ class ThreadMainDemo3 extends Thread { public void run() { for(int x=0; x<60; x++) System.out.println((Thread.currentThread()==this)+"..."+this.getName()+" demo run"); } } class ThreadDemo3 { public static void main(String[] args) { ThreadMainDemo3 d1 = new ThreadMainDemo3(); ThreadMainDemo3 d2 = new ThreadMainDemo3(); ThreadMainDemo3 d3 = new ThreadMainDemo3(); d1.start(); d2.start(); d3.start(); } } /* 售票程序需求: 多个窗口同时卖票 */ class TicketMainDemo1 extends Thread { private static int ticketnum = 100; //共享100张票 public void run() { while(true) { if(ticketnum>0) { System.out.println(Thread.currentThread().getName()+"sale :" + ticket--); } } } } class TicketDemo { public static void main(String[] args) { TicketMainDemo1 t1 = new TicketMainDemo1(); //问题:创建一个对象就有100张票,所以需要让4个对象共享100张票,这里就利用到静态属性 TicketMainDemo1 t2 = new TicketMainDemo1(); TicketMainDemo1 t3 = new TicketMainDemo1(); TicketMainDemo1 t4 = new TicketMainDemo1(); t1.start(); t2.start(); t3.start(); t4.start(); } } /* 创建线程的第二种方法 实现Runnable接口 1.定义类实现Runnable接口 2.覆盖Runnable接口中的run方法 将线程要运行的代码存放在该run方法中 3.通过Thread类建立对象 4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数 为什么要将Runnable接口的子类对象传递给Thread的构造函数 答:因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要 让线程去指定对象的run方法,就必须明确该run方法所属的对象 5.调用Thread类的start方法开启线程并调用Runnable接口的子类的run方法 实现方式和继承方式的区别: 1.实现方式好处在于:避免了单继承的局限性,在定义线程时,建议使用实现方式 2.继承Thread:线程代码存放在Thread子类run方法中 3.实现Runnable,线程代码存放在接口的子类的run方法中 */ class RunnableMainDemo implements Runnable { private int ticketnum = 100; //共享100张票 public void run() { while(true) { if(ticketnum>0) { System.out.println(Thread.currentThread().getName()+"sale :" + ticket--); } } } } class RunnableDemo { public static void main(String[] args) { RunnableMainDemo r = new RunnableMainDemo(); Thread t1 = new Thread(r); //创建了一个线程 Thread t2 = new Thread(r); //创建了一个线程 Thread t3 = new Thread(r); //创建了一个线程 Thread t4 = new Thread(r); //创建了一个线程 t1.start(); t2.start(); t3.start(); t4.start(); } } //多线程的安全问题 class TicketMainDemo2 implements Runnable { private int ticknum = 100; public void run() { while(true) { if(ticknum>0) //线程执行到这里的时候挂了 { try{Thread.sleep(10);}catch(Exception e){} //模拟线程挂掉 System.out.println(Thread.currentThread().getName()+"...sale : " + ticknum--); } } } } class TicketDemo2 { public static void main(String[] args) { TicketMainDemo2 t1 = new TicketMainDemo2(); TicketMainDemo2 t2 = new TicketMainDemo2(); TicketMainDemo2 t3 = new TicketMainDemo2(); TicketMainDemo2 t4 = new TicketMainDemo2(); t1.start(); t2.start(); t3.start(); t4.start(); } } /* 通过分析,发现,打印出0,-1,-2等错票 多线程的运行出现了安全问题: 问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完成 另一个线程参与进来执行,导致贡献数据的错误 解决方案: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中其他线程不可以参与执行 Java对于多线程的安全问题提供了专业的解决方式,就是同步代码块 synchronized(对象) { 需要被同步的代码 } 多线程同步代码块 对象如同锁,持有锁的线程可以在同步中执行 没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁 同步的前提: 1.必须要有2个或2个以上的线程 2.必须是多个线程使用同一个锁 3.保证同步中只能有一个线程在运行 3.保证只同步需要的代码 好处:解决了多线程的安全问题 弊端:多个线程需要判断锁,较为消耗资源 */ class TicketMainDemo3 implements Runnable { private int ticknum = 100; Object obj = new Object(); public void run() { while(true) { synchronized(obj) //同步代码 { if(ticknum>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...sale : " + ticknum--); } } } } } class TicketDemo3 { public static void main(String[] args) { TicketMainDemo3 t1 = new TicketMainDemo3(); TicketMainDemo3 t2 = new TicketMainDemo3(); TicketMainDemo3 t3 = new TicketMainDemo3(); TicketMainDemo3 t4 = new TicketMainDemo3(); t1.start(); t2.start(); t3.start(); t4.start(); } } /* 同步函数 需求: 银行有一个金库 有2个储户分别存300元,每次存100,存3次 */ class BankMainDemo1 { private int sum; //金库 public void add(int n) //对外提供的方法,可以给金库累加 { sum = sum + n; try{Thread.sleep(10);}catch(Exception e){} System.out.println("sum=" + sum); //累加一次打印一次的值 } } class Cus1 implements Runnable //为什么用Runnable,因为储户里面有存钱动作,存在动作被多个人所执行,或者说被多线程所执行 { private BankMainDemo1 b = new BankMainDemo1(); public void run() { for(int x=0; x<3; x++) { b.add(100); //存钱动作 } } } class BankDemo1 { public static void main(String[] args) { Cus1 = c new Cus1(); Thread t1 = new Thread(c); Thread t2 = new Thread(c); t1.start(); t2.start(); } } /* 目的: 该程序是否有安全问题,如果有如何解决? 如何找到问题: 1.明确哪些代码是多线程运行代码 public void add(int n) { sum = sum + n; System.out.println("sum=" + sum); } public void run() { for(int x=0; x<3; x++) { b.add(100); //因为这里调用add方法,所以add方法也是多线程运行代码 } } 2.明确共享数据 private BankMainDemo1 b = new BankMainDemo1(); private int sum; //金库 3.明确多线程运行代码中哪些语句是操作共享数据的 sum:中有两句 sum = sum + n; sum为0,+100赋值给sum,还没等执行到下面的语句,可能会挂在这里,而后者拿到执行权 又来执行这一句,这时sum为200,而此时,有可能前者活了,那么前者接着执行下一句,就会出现直接打印 200的情况,100就无法打印出来,由此分析得出这两句话出了问题 System.out.println("sum=" + sum); //累加一次打印一次的值 */ class BankMainDemo2 { private int sum; //Object obj = new Object(); public synchronized void add(int n) { //synchronized(obj) //同步有问题的代码,注意只同步该同步的代码 //同步代码块,也是一种封装形式,唯一不同的就是具有同步的特性 //如果让函数具备同步特写呢? //{ sum = sum + n; try{Thread.sleep(10);}catch(Exception e){} System.out.println("sum=" + sum); //} } } class Cus2 implements Runnable { private BankMainDemo2 b = new BankMainDemo2(); public void run() { for(int x=0; x<3; x++) { b.add(100); } } } class BankDemo2 { public static void main(String[] args) { Cus2 = c new Cus2(); Thread t1 = new Thread(c); Thread t2 = new Thread(c); t1.start(); t2.start(); } } /* 同步函数的锁是this 函数需要被对象调用,那么函数都有一个所属对象的引用,就是this 所以同步函数使用的锁是this */ class TicketMainDemo4 implements Runnable { private int ticknum = 100; //public synchronized void run() 如果这么做,是不行的,因为其他线程进步来,说白了就是没搞清楚哪些需要同步,哪些不需要 public void run() { while(true) { show(); //show方法一定会被this调用,这里其实省略了this. } } public synchronized void show() //单独把需要同步的代码封装,问题来的,同步函数牛逼就牛逼在锁,那么请问,锁呢? 我们把obj注释了那么这里锁在哪里呢? //同步函数的锁其实就是this { if(ticknum>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...sale : " + ticknum--); } } } class TicketDemo4 { public static void main(String[] args) { TicketMainDemo4 t = new TicketMainDemo4(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } } /* 通过上面的程序进行验证 使用两个线程来卖票 一个线程在同步代码块中 一个线程在同步函数中 都在执行卖票动作 */ class TicketMainDemo5 implements Runnable { private int ticknum = 100; Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(obj) //同步代码块,这里经实验,我们得出需要换成this才行 synchronized(this) { if(ticknum>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...code : " + ticknum--); } } } } else { while(true) { show(); } } } public synchronized void show() //同步函数,锁是this { if(ticknum>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...show... : " + ticknum--); } } } class TicketDemo5 { public static void main(String[] args) { TicketMainDemo5 t = new TicketMainDemo5(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exception e){} t.flag = false; //交换标记 t2.start(); } /* 从运行结果来看,还是不安全,原因在哪里呢?我们要想想同步的前提 同步的前提: 1.必须要有2个或2个以上的线程 //这个没问题 2.必须是多个线程使用同一个锁 //可是这里,我们用的不是同一个锁,一个是obj一个是this,所以我们可以把obj对象换成this 3.保证同步中只能有一个线程在运行 3.保证只同步需要的代码 */ } /* 静态同步函数的锁是Class对象 加static以后就不安全了,原因是静态方法用的锁不是this 因为静态方法中也不可以定义this 静态同步方法,使用的锁是该方法所在类的自解码文件对象。 类名.class */ class TicketMainDemo6 implements Runnable { private static int ticknum = 100; //这里要static boolean flag = true; public void run() { if(flag) { while(true) { synchronized(TicketMainDemo6.class)//类名.class { if(ticknum>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...code : " + ticknum--); } } } } else { while(true) { show(); } } } public static synchronized void show() //加static以后就不安全了,原因是静态方法用的锁不是this,因为静态方法是由类调用的,类加载的时候会生成自解码文件对象,该对象是类名.class 该对象是class { if(ticknum>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...show... : " + ticknum--); } } } class TicketDemo6 { public static void main(String[] args) { TicketMainDemo6 t = new TicketMainDemo6(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exception e){} t.flag = false; //交换标记 t2.start(); } } /* 多线程-单例设计模式: 饿汉式: */ class Single { private Single(){} private static final Single s = new Single(); public static Single getInstance() { return s; } } //懒汉式: class Single { private Single(){} private static Single s = null; public static synchronized Single getInstance() //所以要加synchronized但是一旦上了锁,效率就会变低,因为每次都会去读锁 { if(s==null) { //---Thread-0 //---Thread-1 s = new Single(); //0醒了,new一个对象,1醒了,又new一个对象 } return s; } } /* 为了解决效率问题,我们可以用双重判断来解决 解决方案1: */ class Single { private Single(){} private static Single s = null; public static Single getInstance() { if(s==null) //这里进行双重判断,如果不为空,则不再读锁,减少了判断锁的次数 { synchronized(Single.class) { if(s==null) { s = new Single(); } } } return s; } } //解决方案2: class Single { private Single(){} private static Single s = null; public static Single getInstance() //所以要加synchronized但是一旦上了锁,效率就会变低,因为每次都会去读锁 { if(s==null) { synchronized(Single.class) { if(s==null) { s = new Single(); } } } return s; } } /* 多线程-死锁 同步当作会产生的问题-死锁 多线线程之间互相抢锁,自己都不放锁 通常死锁的出现就是同步中嵌套同步,而锁却不同 */ //死锁例子1: class DeadlockMainDemo1 implements Runnable { private int ticknum = 100; //这里要static Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(obj)//obj锁 { show();//this锁 } } } else { while(true) { show(); } } } public synchronized void show() //this锁 { synchronized(obj) //obj锁 { if(ticknum>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"...code : " + ticknum--); } } } } class DeadlockDemo1 { public static void main(String[] args) { DeadlockMainDemo1 d = new DeadlockMainDemo1(); Thread d1 = new Thread(d); Thread d2 = new Thread(d); d1.start(); try{Thread.sleep(10);}catch(Exception e){} d.flag = false; d2.start(); } } //死锁例子2: class DeadlockMainDemo2 implements Runnable { private boolean flag; DeadlockMainDemo2(boolean flag) { this.flag = flag; } public void run() { if(flag) { synchronized(MyLock.locka) //a锁嵌套b锁 { System.out.println("if locka"); synchronized(MyLock.lockb) { System.out.println("if lockb"); } } } else { synchronized(MyLock.lockb) //b锁嵌套a锁 { System.out.println("else lockb"); synchronized(MyLock.locka) { System.out.println("else locka"); } } } } } class MyLock { static Object locka = new Object(); static Object lockb = new Object(); } class DeadlockDemo2 { public static void main(String[] args) { Thread t1 = new Thread(new DeadlockMainDemo2(true)); Thread t2 = new Thread(new DeadlockMainDemo2(false)); t1.start(); t2.start(); } } /* 多线程之间的通信:其实就是多个线程在操作同一个资源,但是操作的动作不同 */ //安全问题: class ThreadResMainDemo1 { String name; String sex; } class Input implements Runnable { private ThreadResMainDemo1 r; Input(ThreadResMainDemo1 r) { this.r = r; } public void run() { int x = 0; while(true) { if(x==0) { r.name = "没教养的牛"; r.sex = "男"; } else { r.name = "傻馒"; r.sex = "女"; } x = (x+1)%2; } } } class Output implements Runnable { private ThreadResMainDemo1 r; Output(ThreadResMainDemo1 r) { this.r = r; } public void run() { while(true) { System.out.println(r.name+"...."+r.sex); } } } class ThreadResDemo1 { public static void main(String[] args) { ThreadResMainDemo1 r = new ThreadResMainDemo1(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } } /* 产生问题的原因,输入线程还没有执行完毕,被输出线程抢走了执行权,出现了安全问题,那么怎么解决呢? */ class ThreadResMainDemo2 { String name; String sex; } class Input implements Runnable { private ThreadResMainDemo2 r; Input(ThreadResMainDemo2 r) { this.r = r; } public void run() { int x = 0; while(true) { synchronized(r) //添加同步代码块,使用同一把锁 { if(x==0) { r.name = "没教养的牛"; r.sex = "男"; } else { r.name = "傻馒"; r.sex = "女"; } x = (x+1)%2; } } } } class Output implements Runnable { private ThreadResMainDemo2 r; Output(ThreadResMainDemo2 r) { this.r = r; } public void run() { while(true) { synchronized(r) //这里也要同步代码块,使用同一把锁 { System.out.println(r.name+"...."+r.sex); } } } } class ThreadResDemo2 { public static void main(String[] args) { ThreadResMainDemo2 r = new ThreadResMainDemo2(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } } /* 线程间通信-等待唤醒机制 */ class ThreadResMainDemo3 { String name; String sex; boolean flag = false; //用于判断ThreadResMainDemo3中是否有数据,当为false时,Input才能往里写,当写入完成时,置为false,并且Input进入等待状态,让它不再抢占cpu执行权 } class Input implements Runnable { private ThreadResMainDemo3 r; Input(ThreadResMainDemo3 r) { this.r = r; } public void run() { int x = 0; while(true) { synchronized(r) { if(r.flag) //输入之前判断ThreadResMainDemo3中是否有数据,如果有就等待 try{r.wait();}catch(Exception e){} //等待的线程,存在线程池中 if(x==0) { r.name = "没教养的牛"; r.sex = "男"; } else { r.name = "傻馒"; r.sex = "女"; } x = (x+1)%2; r.flag = true; //输入完成后将标记改为true r.notify(); //notify唤醒的都是线程池中的线程,通常唤醒第一个被等待的 } } } } class Output implements Runnable { private ThreadResMainDemo3 r; Output(ThreadResMainDemo3 r) { this.r = r; } public void run() { while(true) { synchronized(r) { if(!r.flag) //这里要取反,因为输入把它置为true了,如果ThreadResMainDemo3没数据,就不需要取数据,所以非真就开始等待 try{r.wait();}catch(Exception e){} System.out.println(r.name+"...."+r.sex); r.flag = false; //取完数据以后把flag置为false表示ThreadResMainDemo3没数据 r.notify(); //唤醒Input } } } } class ThreadResDemo3 { public static void main(String[] args) { ThreadResMainDemo3 r = new ThreadResMainDemo3(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } /* wait(); notify(); notifyAll(); 都使用在同步中,因为要对持有监视器(锁)的线程操作 所以要使用在同步中,因为只有同步才具有锁 为什么这些操作线程的方法要定义在Object类中呢? 因为这些方法在操作同步中线程时,都必须要标识它们所操作的线程只有的锁 只有同一个锁上的被等待线程,可以被同一个锁上的notify();唤醒,不可以 对不同锁中的线程进行唤醒 也就是说等待和唤醒必须是同一把锁,而锁可以是任意对象,所以可以被任意 对象调用的方法定义在Object中 */ } /* 代码优化 */ class ThreadResMainDemo4 { //将属性私有化 private String name; private String sex; private boolean flag = false; //对外提供设置方法 public synchronized void set(String name,String sex) { if(flag) try{this.wait();}catch(Exception e){} this.name = name; this.sex = sex; flag = true; this.notify(); } //对外提供打印方法 public synchronized void outPut() { if(!flag) try{this.wait();}catch(Exception e){} System.out.println(name+"...."+sex); flag = false; this.notify(); } } class Input implements Runnable { private ThreadResMainDemo4 r; Input(ThreadResMainDemo4 r) { this.r = r; } public void run() { int x = 0; while(true) { if(x==0) r.set("没教养的牛","男"); else r.set("傻馒","女"); x = (x+1)%2; } } } class Output implements Runnable { private ThreadResMainDemo4 r; Output(ThreadResMainDemo4 r) { this.r = r; } public void run() { while(true) { r.outPut(); } } } class ThreadResDemo4 { public static void main(String[] args) { ThreadResMainDemo4 r = new ThreadResMainDemo4(); new Thread(new Input(r)).start(); //匿名对象形式 new Thread(new Output(r)).start(); } } /* JDK1.5以后提供了多线程升级解决方案 将同步synchronized替换成实现Lock操作 将Object中的wait,notify,notifyAll,替换了Condition对象 该对象可以Lock锁,进行获取 */ /* 停止线程interrupt(inter乳癌普特) 1.定义循环结束标记: 因为线程运行代码一般都是循环,只要控制了循环即可 2.使用interrupt(中断)方法 该方法是结束线程冻结状态,使线程回到运行状态中来 Stop方法已经过时: 那么如何停止线程呢? 答:只有一种,run()方法结束 原理: 一般开启多线程运行,运行代码通常是循环结构的,只要控制住循环 就可以让run方法结束,也就是线程结束 当没有指定的方式让冻结的线程恢复到运行状态时,这时候需要对冻结的线程进行强制清除 强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束 Thread类提供了该方法:interrupt(); */ class StopThreadMainDemo1 implements Runnable { private boolean flag = true; public synchronized void run() { while(flag) { try { wait(); } catch(InterruptedException e) { System.out.println(Thread.currentThread().getName()+".....Exception"); flag = false; //清除中断状态后,将标记位置为false } System.out.println(Thread.currentThread().getName()+"...run"); } } public void changeFlag() { flag = false; } } class StopThreadDemo1 { public static void main(String[] args) { StopThreadMainDemo1 st = new StopThreadMainDemo1(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); int num = 0; while(true) { if(num++ == 60) { //st.changeFlag(); t1.interrupt(); //中断状态,清除冻结状态 t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"...."+num); } System.out.println("over"); } } /* 守护线程setDaemon(set地模恩) 守护线程也可以理解为后台线程 */ class StopThreadMainDemo2 implements Runnable { private boolean flag = true; public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+".....Exception"); } } public void changeFlag() { flag = false; } } class StopThreadDemo2 { public static void main(String[] args) { StopThreadMainDemo2 st = new StopThreadMainDemo2(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.setDaemon(true); //守护线程(后台线程),该方法必须在启动线程前调用 t2.setDaemon(true); //守护线程(后台线程),该方法必须在启动线程前调用 //后台线程开启后和前台线程共同抢劫cpu执行权 //当所有的前台线程结束后,后台线程自动结束 t1.start(); //这个就叫启动线程 t2.start(); int num = 0; while(true) { if(num++ == 60) { break; } System.out.println(Thread.currentThread().getName()+"...."+num); } System.out.println("over"); } } /* Join方法(抢夺cpu执行权) 当线程执行完毕后,等待的线程才能恢复 用处:当在进行多线程运算的时候,一个线程运算过程中 可以临时加入一个线程,让这个线程运算完,其他线程 在运行 特点: 当A线程执行到了B线程的.join()方法时,A线程就会等待 等B线程执行完,A才会执行,Join可以用来临时加入线程 执行 */ class JoinMainDemo1 implements Runnable { public void run() { for(int x=0; x<70; x++) { System.out.println(Thread.currentThread().getName()+"....Join as" + x); } } } class JoinDemo1 { public static void main(String[] args)throws Exception { JoinMainDemo1 j1 = new JoinMainDemo1 Thread t1 = new Thread(j1); Thread t2 = new Thread(j1); t1.start(); t1.join(); //t1要申请加入到运行中来,更确定点说就是t1要执行权,也就是抢夺cpu执行权 t2.start(); for(int x=0; x<80; x++) { System.out.println("main...." + x); } System.out.println("Main Over"); } } /* 优先级&yield方法 线程组:一般情况下,谁开启的线程,那么该线程就属于哪个组 优先级:优先级代表着抢夺资源的频率setPriority() yield()方法用于暂停当前正在执行的线程对象,并执行其他线程 达到减缓线程的运行,能让其他线程也有平均抢资源的机会 */ class yeieldMainDemo1 implements Runnable { public void run() { for(int x=0; x<70; x++) { System.out.println(Thread.currentThread().toString()+"....Join as" + x); Thread.yield(); //强制让执行权临时释放 } } } class yeieldDemo1 { public static void main(String[] args)throws Exception { yeieldMainDemo1 y1 = new yeieldMainDemo1(); Thread t1 = new Thread(y1); Thread t2 = new Thread(y1); t1.start(); t1.setPriority(Thread.MAX_PRIORITY); //设置线程优先级为10 t2.start(); for(int x=0; x<80; x++) { System.out.println("main...." + x); } System.out.println("Main Over"); } } /* 开发时候如何正确写线程 什么时候用多线程? 答:当某些代码需要同时被执行时,就用单独的线程进行封装 */ class ThreadMainDemo4 { public static void main(String[] args) { //封装第一个线程 new Thread() { public void run() { for(int x=0; x<100; x++) { System.out.println(Thread.currentThread().getName()+"...."+x); } } }.start(); //封装第二个线程 Runnable r = new Runnable() { public void run() { for(int x=0; x<100; x++) { System.out.println(Thread.currentThread().getName()+"...."+x); } } }; new Thread(r).start(); //主线程 for(int x=0; x<100; x++) { System.out.println(Thread.currentThread().getName()+"...."+x); } } }
时间: 2024-11-11 22:18:55