线程
线程是操作系统运算调度的最小单位
任务,多线程,进程
进程是一个程序的执行的过程,它是一个动态的概念,是系统资源分配的单位,里面有若干个线程
-
线程就是独立的执行路径
-
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如:主线程,gc线程
-
main()称之为主线程,为系统入口,用于执行整个程
Thread class → 继承Thread(重点)
public class TestThread extends Thread{ @Override public void run() { System.out.println("54654"); } public static void main(String[] args) { TestThread testThread=new TestThread(); //调用start()方法开启多线程,交替执行,同时执行 testThread.start(); //先执行run方法在执行后面的输出 testThread.run(); System.out.println("78465154"); } }
Runnable接口 → 实现Runnable接口(重点)
//创建线程方式2,实现Runable接口,重写run方法,执行线程需要丢入runable接口实现类,调用start方法 public class RunTest3 implements Runnable{ @Override public void run() { System.out.println("546"); } public static void main(String[] args) { RunTest3 runTest3=new RunTest3(); //创建线程对象,通过线程对象来开启线程,代理 Thread thread=new Thread(runTest3); thread.start(); } }
抢票问题
package XianChen; public class TestThread4 implements Runnable{ private int ticket=10; @Override public void run() { try { Thread.sleep(200);//延时2s } catch (InterruptedException e) { e.printStackTrace(); } while (ticket!=0){ System.out.println(Thread.currentThread().getName()+"拿到第"+ticket--+"票"); } System.out.println("票以售空"); } public static void main(String[] args) { TestThread4 testThread4=new TestThread4(); new Thread(testThread4,"小明").start(); new Thread(testThread4,"小红").start(); new Thread(testThread4,"小光").start(); } }
龟兔赛跑
public class TestThread5 implements Runnable { private String winner; public void run() { for (int i = 0; i <= 100; i++) {//赛道距离为100 boolean flag=gameover(i); if(flag) { break; } System.out.println(Thread.currentThread().getName() + "跑了" + i + "步"); } } public boolean gameover(int steps){ if(winner!=null) {//当胜利者存在时,两个线程的共同参数 return true; } else if(steps >= 100) { winner = Thread.currentThread().getName(); System.out.println("胜利者是" + winner); return true; } return false; } public static void main(String[] args) { TestThread5 testThread5=new TestThread5(); new Thread(testThread5,"兔子").start(); new Thread(testThread5,"乌龟").start(); } }
Callable接口 → 实现Callable接口(了解)
静态代理
-
真实对象和代理对象都要实现同一个接口
-
代理对象要代理真是角色
优点
代理对象可以做很多真实对象做不了的事情
例如: 你:真是对象
婚前公司:代理,帮你处理结婚的事情 相当于 Thread
结婚:两者都是实现结婚这件事,
Lamda表达式
public class lambda { public static void main(String[] args) { //lambda表达式 Wed wed2=(int a)->{ System.out.println("68746"); }; wed2.ol(7); 简化后 Wed wed2=(a)->System.out.println("68746"); }
优点
-
避免匿名内部类定义过多
-
可以让代码看起来更加简洁
-
去掉了一些没有意义的代码,只留下核心的逻辑
1,函数式接口,一个接口里面只包含一个抽象方法 public interface Runable{ void run(); }
线程停止
package XianChen; //测试Stop //建议线程正常停止--->利用次数,不建议死循环 //建议使用标志位---->设置一个标志位 //不要使用stop或者destroy等过时或者jdk不建议使用的方法 public class StopTest implements Runnable { boolean flag=true; int i=0; @Override public void run() { while (flag){ System.out.println("result: "+i++); } } public void stop(){ this.flag=false; } public static void main(String[] args) { StopTest stopTest=new StopTest(); new Thread(stopTest).start(); for (int i = 0; i < 1000; i++) { System.out.println("main"+i); if(i==900){ stopTest.stop(); System.out.println("线程该停止了"); } } } }
线程休眠sleep
-
sleep(时间)指当前线程阻塞的毫秒数
-
sleep存在异常InterruptException
-
sleep时间达到后线程进入就绪状态
-
sleep可以模拟网络延时,倒计时等
-
每一个对象都有一个锁,sleep不会释放锁
package XianChen; import java.sql.DatabaseMetaData; import java.text.SimpleDateFormat; import java.util.Date; public class SleepTest { private int a=10; public void sleep() throws InterruptedException{ while (a>=0){//倒计时 System.out.println(""+a--); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { SleepTest sleepTest = new SleepTest(); Date date=new Date(System.currentTimeMillis());//获取系统时间 while (true) { try { Thread.sleep(1000);//延时一秒 System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));//输出当前系统时间 date=new Date(System.currentTimeMillis());//更新当前时间赋值给date } catch (InterruptedException e) { e.printStackTrace(); } } } }
线程礼让Yield
-
让当前正在执行的线程暂停,但不阻塞
-
将线程转换为就绪状态
-
让cpu重新调度,礼让不一定成功
观察状态
Thread.State state =Thread.getState(); System.out.pritn(state);
线程的优先级priority
程序先执行优先级高的
public class PriorityTast { public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+" "+Thread.currentThread().getPriority());//主线程优先级 priority priority=new priority(); Thread t1=new Thread(priority); Thread t2=new Thread(priority,"2"); Thread t3=new Thread(priority,"3"); //先设置优先级,在输出 t1.start(); t2.setPriority(4);//设置优先级 t2.start(); t3.setPriority(Thread.MAX_PRIORITY); t3.start(); } } class priority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+" "+Thread.currentThread().getPriority()); } }
守护线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不必等待守护线程执行完毕
package XianChen; public class DaemonTast { public static void main(String[] args) { people people=new people(); God god=new God(); Thread t1=new Thread(god); Thread t2=new Thread(people); t1.setDaemon(true);//默认为false表示是用户线程,设置为true时为守护线程,正常的线程都为用户线程 t1.start();//守护线程启动 t2.start();//用户线程启动 } } class people implements Runnable{ @Override public void run() { int count=365; while (count>=0) { count--; System.out.println("you live happy"); } System.out.println("everthing is over"); } } class God implements Runnable{ @Override public void run() { while (true) { System.out.println("protect you all the time"); } } }
线程同步
并发:一个对象被多个线程同时执行(列如:抢票)
形成条件:队列+锁(synchronized) 保证线程同步的安全性
存在问题
-
一个线程持有锁会导致其他所有需要此锁的线程挂起(排队上厕所 锁相当于门)
-
多个线程竞争下,会导致性能下降
-
一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题
同步方法和同步和代码块
synchronized方法和synchronized代码块 public synchronized void methon(){ } synchronized(object){//对象为变量 } //银行取钱 public class TicketTast { public static void main(String[] args) { Account account=new Account(100,"共同资金:"); bank you=new bank(account,50,"你"); bank people=new bank(account,100,"朋友"); you.start();//开启线程 people.start(); } } //账户 class Account { int money;//余额 String name;//账户名 public Account(int money, String name) { this.money = money; this.name = name; } } //银行 class bank extends Thread { Account account; int drawingmoney; int nowmoney; String name; public bank(Account account, int drawingmoney, String name) { super(name); this.account = account; this.drawingmoney = drawingmoney; } @Override public void run() { synchronized (account) {//synchroized块对账户account进行锁定 System.out.println(account.name + account.money); if (account.money - drawingmoney < 0) { System.out.println(Thread.currentThread().getName() + "的余额不足,取不了"); return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //银行卡内余额=当前账号余额-取出来的钱 account.money = account.money - drawingmoney; System.out.println(Thread.currentThread().getName() + " 取了钱目前卡内剩下余额:" + account.money); } } } 本身安全的集合 copyOnwriteArrayList list=new copyOnwriteArrayList();
死锁(隐式)
当某一个同步块同时拥有“两个以上对象的锁时”,就会发生死锁问题
package XianChen; import Nei.Ma; public class LockTast { public static void main(String[] args) { Makeup m1=new Makeup("白雪公主",0); Makeup m2=new Makeup("灰姑娘",1); new Thread(m1).start(); new Thread(m2).start(); } } //镜子 class Mirror{ } //口红 class Lipstick{ } class Makeup extends Thread{ String name;//化妆的人 int choie; //需要的资源只有一份,用static类来保证 static Mirror mirror=new Mirror(); static Lipstick lipstick=new Lipstick(); @Override public void run() { try { makeup(); } catch (InterruptedException e) { e.printStackTrace(); } } public Makeup(String name,int choie){ this.name=name; this.choie=choie; } public void makeup() throws InterruptedException { if(choie==0){//同时拥有两个锁会导致程序停止运行 synchronized(mirror){ System.out.println(this.name+"拿了镜子");//镜子锁 } Thread.sleep(2000);//延时一秒后拿下一个东西 synchronized(lipstick){ System.out.println(this.name+"拿了口红");//口红锁 } }//同时拥有两个锁会导致程序停止运行 else { synchronized(lipstick){ System.out.println(this.name+"拿了口红"); } Thread.sleep(1000);//延时一秒后拿下一个东西 synchronized(mirror){ System.out.println(this.name+"拿了镜子"); } } } }
Lock(显示)
-
Lock接口是控制多个线程对共享资源进行访问的工具
-
ReentrantLock类实现了Lock
package XianChen; import java.util.concurrent.locks.ReentrantLock; public class LockTast1 { public static void main(String[] args) { Locktast2 locktast=new Locktast2(); new Thread(locktast).start(); new Thread(locktast).start(); new Thread(locktast).start(); } } class Locktast2 implements Runnable{ int ticket=10; ReentrantLock lock=new ReentrantLock();//设置锁 @Override public void run() { try { lock.lock();//开锁 while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (ticket > 0) { System.out.println(ticket--); } else { break; } } }finally { lock.unlock();//关锁 } } }
生产者消费者问题
管程法 public class PcTast { public static void main(String[] args) { Factor factor=new Factor(); Protect protect=new Protect(factor); Consumer consumer=new Consumer(factor); protect.start(); consumer.start(); } } //生产者 class Protect extends Thread{ Factor container; Protect( Factor container){ this.container=container; } @Override public void run() { for (int i = 1; i < 100; i++) { System.out.println("生产了"+i+"只"); container.push(new duck(i));//将i的值赋值个id } } } //消费者 class Consumer extends Thread{ Factor container; Consumer( Factor container){ this.container=container; } @Override public void run() { for (int i = 1; i < 100; i++) { System.out.println("消费了"+container.pop().id+"只"); } } } //产品 class duck{ int id;//编号 public duck(int id){ this.id=id; } } class Factor{ //容器计数器 int count=0; //容器大小 duck[] ducks=new duck[10]; //生产 public synchronized void push(duck id){ //容器满了 if(count==ducks.length){ //等待消费者消费,生产者等待, try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { //生产商品 ducks[count]=id;//将i从1-10分别赋值给数组0-10 count++; //生产完毕,通知消费者 this.notifyAll(); } } //消费 public synchronized duck pop(){ // if(count==0){ //等待生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //消费者消费 count--; duck id=ducks[count];//dunk为编号id //消费玩了,通知生产者 this.notifyAll(); return id; } }