thread 线程毛线(真正执行的是线程,main线程,gc线程)
process 进程过程(系统分配进程,是一个单位,在进程里跑线程,保护伞,把所有线程放在里面)
单核cpu,同一时间只能做一件事情,如果做多个事情,线程之间切换很快,感觉不出来切换,看电影,声音、影像……一起执行
实现线程的三种方法:1、thread类 2、runable接口 3、callable接口
一、thread类继承runable接口
callable(了解一下,目前不重要)
第一种方法:继承Thread类
public class Demo01 extends Thread{//类要从这里继承,出错:下面再定义一个类,就只能static才能访问 @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("这是一个继承的线程"+i); } } } public static void main(String[] args) { Demo01 thread01 = new Demo01(); thread01.start();//用的是start方法 System.out.println("======================"); for (int i = 0; i <2000 ; i++) { System.out.println("这是一个主线程"+i); } } }
调用start()方法;先执行主线程,中间穿插执行继承的线程,两个线程交替执行。
总结:线程开启不一定立即执行,由cpu调度。
下载图片的流程思考:1、创建ThreadTest类,2、先导入一个Download类下载图片类包(传入url、filename),3、写Download类,4、ThreadTest类继承继承Thread类,5、(重点)重新run方法,执行DownLaod对象的downLaod方法(创建Download类对象,传入url,filename),《url,和filename哪里来呢?》,6、ThreadTest两个属性(rul,filename),7、重写构造方法(this.url=url;this.filename=filename)(6和7的方法是传参给run方法),8、然后创建主方法,在主方法中ThreadTest创建对象t1,t2(构造方法需要传参)传入(rul,filename),9、t1.start() t2.start()执行。执行结果谁先下载完谁先执行完,不是先后,而是一起。
二、第二种方法:实现Runnable接口(推荐使用实现接口,而不是继承Thread类)
步骤和继承Thread类一样,只是最后要用静态代理new Thread(testRunable(类的对象)).start();
优势:方便灵活,方便同一对象被多个线程使用。
问题:下面的代码,多个线程操作同一个资源,会造成多个人拿同一张票
静态代理类
public class Demo02 implements Runnable{ int ticktsNumber=100; @Override public void run() { while(ticktsNumber>0){ System.out.println(Thread.currentThread().getName()+ticktsNumber+"张票"); ticktsNumber--; } } public static void main(String[] args) { Demo02 demo02 = new Demo02(); new Thread(demo02,"小明").start(); new Thread(demo02,"小华").start(); new Thread(demo02,"小天").start(); } }
线程的启用:多个线程操作同一个对象
三、静态代理类(婚庆公司的例子)
真实对象和代理对象都要实现同一个接口代理对象要代理真实角色 private String
public class Demo03 { public static void main(String[] args) { WeddingConpany weddingConpany = new WeddingConpany(new You()); weddingConpany.HappyMerry(); } }//注意上面是Demo03类,下面是其他类,如果卸载Demo03的括号里,出现需要将下面类转为static类才能调用的提示!!!出现过很多次这种情况了 interface Merry{ void HappyMerry(); } class You implements Merry{ @Override public void HappyMerry() { System.out.println("我要结婚啦!"); } } class WeddingConpany implements Merry{ private Merry target; public WeddingConpany(Merry target){//构造方法中传参,传入对象 this.target=target; } @Override public void HappyMerry() { before(); this.target.HappyMerry();//this这个类的target,执行方法 after(); } void before(){ System.out.println(target+"我要结婚啦"); } void after(){ System.out.println(target+"结婚后"); } }
优点:代理对象可以做真实对象做不了的事情,真实对象专注做自己的事情
四、Lambda 函数式编程
一个抽象接口(interface),只有一个抽象方法(abstract)
1、外部类,写在类的{}外面
2、静态内部类 static修饰,写在类{}的里面
3、局部内部类,写在方法{}里面
4、匿名内部类:对象直接实现接口,取消类实现接口的环节(原来是类实现接口,对象实现类)
5、Lambda简化(其实是从上面,一步一步省略下来的,类或接口中只有唯一的一个方法才能省略,)
public class Demo04 { public static void main(String[] args) { ILove love=(String a)->{ //接口 对象 =(传参) System.out.println("i love you "+a); }; love.iLove("小明");//对象调用接口方法 }; } interface ILove { //接口定义方法 void iLove(String a); }
五、网络延时 模拟网络延时的作用,放大问题的发生性,阻塞状态
1、sleep(ms)
重点记一句话:每个对象都有一把锁,sleep不会释放锁
public class Demo06 { public static void main(String[] args) throws InterruptedException { Date date = new Date(System.currentTimeMillis()); while (true){ Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH.mm.ss").format(date)); date=new Date(System.currentTimeMillis()); } } }
2、yield 线程礼让, 礼让不一定成功,看cpu心情
3、join 优先插队
public class Demo07 implements Runnable{ @Override public void run() { for (int i = 0; i <1000 ; i++) { System.out.println("vip来啦"+i); } } //测试结果和教程不一样,每次join的位置不一样,而且是交叉跑,不是vip跑完再跑main public static void main(String[] args) throws InterruptedException { Demo07 demo07 = new Demo07(); Thread thread = new Thread(demo07); thread.start(); for (int i = 0; i <300 ; i++) { if(i==200){ thread.join(); } System.out.println("main线程"+i); } }
thread1.start();//线程结束后,不能再次开启,一次性的。除非再new对象
}
4、线程优先级priority
set priority(5) ()括号里是常量,优先级,权重,默认优先级是5,最大是10,最小是1
5、守护线程 daemon
线程分为 用户线程 (main线程)、守护线程(gc(垃圾回收线程隐藏了))
注意:守护线程等待用户线程执行完毕,自动结束,虚拟机不用等待守护线程结束。
thread.setDaemon(trun); 默认用户线程都是flase
6、线程的同步 锁synchronized(隐式的)
队列+锁(排队上厕所,锁门)。弊端(有人3s解决完,还要等这个30min的人解决完才能进)
7、如何让线程变得安全(不安全的三个案例,买票,取钱)
8、同步方法、同步块
对方法加synchronized修饰,就会自动获得一把锁,变成同步方法
同步块
锁的是代码中变化的量,增删改。
JUC,java.util.concurrent包(并发包),
9、死锁:多个线程互相抱着对方需要的资源,不放手
10、Lock锁(显示的)ReentrantLock类实现Lock
public class Demo09 { public static void main(String[] args) { SellTicket sellTicket = new SellTicket(); new Thread(sellTicket).start(); new Thread(sellTicket).start(); new Thread(sellTicket).start(); } } class SellTicket implements Runnable { int ticket = 10; private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true) { try { lock.lock(); if (ticket>0){ Thread.sleep(1000); System.out.println(ticket--); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } }
六、线程协作
wait();等待
notify();唤醒
使用线程池:ExcutorService