多线程
-
进程:是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。
-
线程:通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是cpu调度和执行的单位。线程是一个独立的执行路径
- 继承Thread类
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 不建议使用:避免oop单继承局限性
package com.Lv.TestThread; /** * @Author: Lv * @Description:多线程 (线程开启不一定立即执行,由cpu调度) * @Vision: 1.0 * @Date: Created in 14:31 2020/7/4 */ public class TestThread01 extends Thread { //子线程 @Override public void run() { for (int i = 0;i < 20;i++){ System.out.println("我在学java---" + i); } } //主线程 public static void main(String[] args) { TestThread01 tt1 = new TestThread01(); tt1.start();//开启线程 调用start()方法,不能调用run()方法 for (int i = 0;i < 200;i++){ System.out.println("我在学多线程---" + i); } } }
-
实现Runnable接口
-
实现接口Runnable具有多线程能力
-
启动线程:传入目标对象+Thread对象.start()
-
推荐使用:避免单继承局限性,灵活方便,方便同一个对象呗多个线程使用
package com.Lv.TestThread; /** * @Author: Lv * @Description:线程写法2:实现Runnable接口 * @Vision: 1.0 * @Date: Created in 15:41 2020/7/4 */ public class TestThread03 implements Runnable { @Override public void run() { for(int i = 0;i < 20;i++){ System.out.println("我在学习java---"+i); } } public static void main(String[] args) { TestThread03 thread03 = new TestThread03(); new Thread(thread03).start(); for(int i = 0;i < 200;i++){ System.out.println("我在学习多线程---"+i); } } }
package com.Lv.TestThread; /** * @Author: Lv * @Description:多线程之龟兔赛跑 * @Vision: 1.0 * @Date: Created in 16:22 2020/7/4 */ public class Race implements Runnable { private static String winner; @Override public void run() { for (int i = 0;i <=100;i++){ if ((Thread.currentThread().getName().equals("兔子"))&&(i%10==0)){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } 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 is:" + winner); return true; } } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race,"兔子").start(); new Thread(race,"乌龟").start(); } }
-
- 继承Thread类
lambda表达式
-
避免匿名内部类过多
-
其实质属于函数式编程的概念
-
用lambda表达式的前提是函数式接口
-
函数式接口:
-
任何接口,如果只包含唯一一个抽象方法,则称之为函数式接口
-
表达式:
-
如果方法中只有一行代码,就可以简化为一行
a-->System.out.print(a); //a为参数
-
如果方法中有多行代码,则加上花括号写成代码块
(a,b)-->{System.out.print(a); //a、b为参数 System.out.print(b); }
-
多线程常用方法
- setPriority(int newPriority) :更改线程的优先级
- static void sleep(long millis):在指定的好描述内让当前正在执行的相处休眠
- void join():等待该线程终止
- static void yeild():暂停当前正在执行的线程对象,并执行其他线程
- void interrupt():中断线程,别用这个方式
- boolean isAlive():测试线程是否处于活动状态
停止线程
- 不推荐使用JDK提供的 stop()、destory()方法(已废弃)
- 推荐线程自己停止下来
- 建议使用一个标志位进行终止变量。当flag=false,则终止线程运行
package com.Lv.TestThread;
/**
* @Author: Lv
* @Description:线程停止
* @Vision: 1.0
* @Date: Created in 19:39 2020/7/4
*/
public class TestStopThread implements Runnable {
private boolean flag = true;
@Override
public void run() {
while (flag){
System.out.println("子线程。。。。。。。。。。。");
}
}
public void stop(){
flag = false;
}
public static void main(String[] args) {
TestStopThread stopThread = new TestStopThread();
new Thread(stopThread).start();
for (int i = 0; i < 100; i++) {
System.out.println(i + "主线程。。。。。。。");
if (i == 90) {
stopThread.stop();
System.out.println("这个线程该休息了。。。。。");
}
}
}
}
线程调度
调整线程优先级
- setPriority(int):设置优先级
- getPriority():读取优先级
- MAX_PRORITY:取值为10,表示最高优先级
- MIN_PRORITY:取值为1,表示最低优先级
- NORM_PRORITY:取值为5,表示默认优先级
线程让步
线程让步指当前运行的线程调用yield()方法暂时放弃cpu,给其他线程一个执行的机会,但这种方式只给相同或更高优先级的线程以执行机会,如果当前系统中没有相同或更高优先级的线程,yield()方法调用不会产生任何效果,当前线程依然占有cpu。
合并线程
调用join()方法,则当前线程被挂起,直到目标线程执行结束它才会恢复。还可在join()方法带一个超市参数,若超时目标线程还未结束,join()方法也能返回。
守护线程
setDaemon(true)方法把一个用户线程设置为守护线程,isDaemon()用来判断一个线程是否为守护线程。(好比将守护线程比作上帝,用户线程比作一个人,上帝从一个人一出生就保佑着他一直到这个人死亡,上帝对这个人的保佑也结束,但是上帝是一直存在的)
线程同步
-
处理多线程是,多个线程访问同一个对象,并且某些线程还想修改这个对象,这时候我们就需要线程同步。线程同步其实就是一种等待机制,多个线程需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程在使用。
-
队列和锁
锁机制:每个对象都有一把锁。由于多个线程访问一个对象,虽然方便但也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入了锁机制,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可。但也有以下问题:
- 一个线程持有锁会导致其他所有需要此锁的线程挂起;
- 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
- 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级导致,引起性能问题;
-
同步方法:synchronized关键字,包括synchronized方法和synchronized块。缺陷:影响效率。synchronized默认锁当前对象this.锁的是需要增删改查变动的代码。
package com.Lv.TestThread; /** * @Author: Lv * @Description: * @Vision: 1.0 * @Date: Created in 9:34 2020/7/5 */ public class UnSafeThread implements Runnable { private int tickets = 10; //票数 boolean flag = true; //外部停止线程标志 @Override public synchronized void run() { //买票 while (flag){ isBuy(); } } //synchronized 同步方法,锁住当前对象 public void isBuy(){ //判断票是否卖完 if (tickets <= 0){ flag = false; } System.out.println(Thread.currentThread().getName()+"买到了第"+tickets--+"张票"); public static void main(String[] args) { UnSafeThread unSafeThread = new UnSafeThread(); new Thread(unSafeThread,"小明").start(); new Thread(unSafeThread,"老师").start(); new Thread(unSafeThread,"黄牛").start(); } }
-
死锁:两个进程都想获得对方持有的锁,但是又互相不释放锁。
package com.Lv.TestThread; /** * @Author: Lv * @Description: * @Vision: 1.0 * @Date: Created in 11:37 2020/7/5 */ public class DeadLock { public static void main(String[] args) { play p1 = new play(0,"小明"); play p2 = new play(1,"小华"); p1.start(); p2.start(); } } //玩具汽车 class ToyCar { } //玩具娃娃 class ToyBaby{ } class play extends Thread { static ToyCar toyCar = new ToyCar(); static ToyBaby toyBaby = new ToyBaby(); int choice; String name; play(int choice,String name){ this.choice = choice; //选择 this.name = name; //对象名字 } @Override public void run() { if ((choice == 0)){ synchronized (toyCar){ System.out.println(this.name+"获得玩具汽车"); try { Thread.sleep(1000); synchronized (toyBaby){ System.out.println(this.name+"获得玩具娃娃"); } } catch (InterruptedException e) { e.printStackTrace(); } } //解决办法:将这段代码块拿出来 // synchronized (toyBaby){ // System.out.println(this.name+"获得玩具娃娃"); // } }else{ synchronized (toyBaby){ System.out.println(this.name+"获得玩具娃娃"); try { Thread.sleep(2000); synchronized (toyCar){ System.out.println(this.name+"获得玩具汽车"); } } catch (InterruptedException e) { e.printStackTrace(); } } // synchronized (toyCar){ // System.out.println(this.name+"获得玩具汽车"); // } } } }
-
Lock显式锁:
-
定义方法:new ReentrantLock();
package com.Lv.TestThread; import java.util.concurrent.locks.ReentrantLock; /** * @Author: Lv * @Description: * @Vision: 1.0 * @Date: Created in 13:19 2020/7/5 */ public class TestLock implements Runnable { int tickets = 10; private final ReentrantLock lock = new ReentrantLock(); //定义锁 @Override public void run() { while (true){ try { //加锁 lock.lock(); if (tickets>0){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tickets--); }else{ break; } }finally { lock.unlock(); //解锁 } } } public static void main(String[] args) { TestLock lock = new TestLock(); new Thread(lock).start(); new Thread(lock).start(); new Thread(lock).start(); } }
-
-
-
线程同步的两种方式
package com.Lv.TestThread; /** * @Author: Lv * @Description: 线程同步,管程法 * @Vision: 1.0 * @Date: Created in 13:54 2020/7/5 */ public class TestPC { public static void main(String[] args) { Home home = new Home(); new Productor(home).start(); new Consume(home).start(); } } //生产者 class Productor extends Thread { Home home; public Productor(Home home){ this.home = home; } //生产 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("生产了"+i+"只鸡"); home.push(new Chicken(i)); } } } //消费者 class Consume extends Thread { Home home; public Consume(Home home){ this.home = home; } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了"+home.pop().id+"只鸡"); } } } //产品 class Chicken { int id; //产品id public Chicken(int id) { this.id = id; } } //存放区 class Home { Chicken[] chickens = new Chicken[10]; int count = 0; //容器计数器 //生产者放入产品 public synchronized void push(Chicken chicken){ //如果容器满了,通知消费者消费 if(count == chickens.length){ //通知消费者消费,生产者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有满,就需要放入产品 chickens[count] = chicken; count++; //可以通知消费者消费了 this.notify(); } //消费者消费产品 public synchronized Chicken pop(){ //判断能否消费 if (count == 0){ //等待生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果可以消费 count--; Chicken chicken = chickens[count]; //通知生产者生产 this.notify(); return chicken; } }
package com.Lv.TestThread; /** * @Author: Lv * @Description:线程同步,信号灯法 * @Vision: 1.0 * @Date: Created in 14:51 2020/7/5 */ public class TestPC02 { public static void main(String[] args) { Tv tv = new Tv(); new Player(tv).start(); new Viewer(tv).start(); } } //生产者 class Player extends Thread { Tv tv; public Player(Tv tv){ this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { if (i % 2 == 0){ tv.paly("快乐大本营。。。。。"); }else{ tv.paly("抖音。。。。。"); } } } } //消费者 class Viewer extends Thread{ Tv tv; public Viewer(Tv tv){ this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { tv.look(); } } } //产品——节目 class Tv{ //生产判断标志位,默认true,true就生产,false就停止(即:生:true,消:false) private boolean flag = true; String voice; //表演 public synchronized void paly(String voice){ if (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演员表演了--->"+voice); this.voice = voice; this.flag = !flag; //通知观众观看 this.notifyAll(); } //观看 public synchronized void look(){ if (flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("观众观看了--->"+voice); this.flag = !flag; this.notifyAll(); } }
-
线程池
- ExecutorService:真正的线程池接口。
- 创建:ExecutorService service = Excutors.newFixedThreadPool(num);参数为线程池大小
- void execute(Runnable commend):执行任务,没有返回值,一般用来执行Runnable
Future submit(Callable task):执行任务,有返回值,一般执行Callable - void shutdown():关闭连接池
- ExecutorService:真正的线程池接口。