多线程

线程的创建

  • 线程开启不一定立即执行,会与主线程交替执行,由cpu调度。
  • 推荐使用实现Runnable接口,避免单继承局限性,方便同一个对象被多个线程使用。
  • 多个线程操作同一个资源,线程不安全,数据紊乱。

继承Thread类

public class Thread1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("aaa"+i);
        }
    }

    public static void main(String[] args) {
        //创建线程对象
        Thread1 t = new Thread1();

        //调用start()方法,开启线程
        t.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("bbb"+i);
        }
    }
}

实现Runnable接口

public class Thread2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            //使线程休眠200纳秒
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("aaa"+i);
        }
    }

    public static void main(String[] args) {
        //创建线程对象
        Thread2 t = new Thread2();

        //调用start()方法,开启线程
        new Thread(t).start();		//可以new Thread(t,"小明").start();小明是这个线程的名字

        for (int i = 0; i < 20; i++) {
            System.out.println("bbb"+i);
        }
    }
}

实现Callable接口

import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) {
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread());
        new Thread(futureTask).start();
        try {
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread");
        return 100;
    }
}

静态代理

  • 真实对象和代理对象都要实现同一个接口
  • 代理对象要代理真实角色
  • 代理对象可以做真实对象做不了的事
public class Test{
    public static void main(String[] args) {
        WeddingCompany wc = new WeddingCompany(new You());
        wc.HappyMarry();
    }
}

interface Marry{
    void HappyMarry();
}

//真实角色类
class You implements Marry{

    @Override
    public void HappyMarry() {
        System.out.println("结婚");
    }
}

//代理类
class WeddingCompany implements Marry{

    private Marry marry;

    public WeddingCompany(Marry marry) {
        this.marry = marry;
    }

    @Override
    public void HappyMarry() {
        before();
        this.marry.HappyMarry();
        after();
    }

    private void before() {
        System.out.println("结婚前");
    }

    private void after() {
        System.out.println("结婚后");
    }
}

lambda表达式写线程

new Thread(
    ()-> System.out.println("我爱你")  //lambda表达式简化一个接口中唯一需要被实现的方法,在这里是run();
).start();

线程方法

线程停止

线程停止一般使用自定义的方法

public class Thread2 implements Runnable {
    //设置标识位
    private boolean flag = true;
    
    @Override
    public void run() {
        while(flag){
            System.out.println("方法");
        }
    }

    //自定义停止方法
    public void stop(){
        this.flag = false;
    }
    
    public static void main(String[] args) {
        Thread2 t =new Thread2();
        new Thread(t).start();
        t.stop();           //停止线程
    }
}

线程休眠

  • 每个对象都有一个锁,线程休眠不会释放锁
  • 线程休眠可以放大问题细节
try {
	Thread.sleep(1000);
} catch (InterruptedException e) {
	e.printStackTrace();
}

线程礼让

使运行中的线程转为就绪状态,cpu重新选择线程调度,礼让不一定成功,cpu也可能还是选择礼让的线程。

A运行中,B就绪,A礼让,A就绪,cpu重新选择A运行还是B运行
Thread.yield();

线程插队

线程插队由线程对象执行,强制执行要求的线程,执行完再执行主线程。

Thread thread =new Thread();
try {
	thread.join();
} catch (InterruptedException e) {
	e.printStackTrace();
}

观察线程状态

Thread.State state = thread.getState();		//thread是线程对象,可直接输出state

线程可以处于以下状态之一: 
NEW 				尚未启动的线程处于此状态。 
RUNNABLE 			在Java虚拟机中执行的线程处于此状态。 
BLOCKED 			被阻塞等待监视器锁定的线程处于此状态。 
WAITING 			正在等待另一个线程执行特定动作的线程处于此状态。 
TIMED_WAITING 		正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 
TERMINATED 			已退出的线程处于此状态。 

一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。 

返回当前线程对象及其名字

Thread.currentThread();					//返回当前线程对象
Thread.currentThread().getName();		//返回当前线程对象名字

线程优先级

  • 线程优先级高不一定先执行,但是先执行的概率更大,优先级1~10。

  • 线程要先设置优先级再启动,一般不设置,默认5。

Thread.getPriority();		//查看线程优先级
thread.setPriority(6);		//设置线程优先级

守护线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕,一般指main()
  • 虚拟机不用等待守护线程执行完毕就可以停止
  • 如后台记录操作日志,监控内存,垃圾回收等
thread.setDaemon(true);			//默认为false表示用户线程,正常的线程都是用户线程,设置为true表示守护线程

线程同步

解决多个线程操作同一个资源,线程不安全,数据紊乱问题。

synchronized 关键字

监视方法内的对象
class BuyTicket implements Runnable{

    int ticketNums = 100000;
    
    @Override
    public void run() {
        buy();
    }

    private synchronized void buy() {
        while(true){
            if(ticketNums>0){
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName()+":"+ticketNums--);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                break;
            }
        }
    }
}
synchronized(监视线程对象){方法}

import java.util.List;

public class SellTicket  implements  Runnable{

    int tickets=100;
    
    public void run() {
        while(true) {
            synchronized(this) {
                if(tickets>0) {
                    try {
                        Thread.sleep(0);
                    }
                    catch(Exception x) {}
                    System.out.println(Thread.currentThread().getName()+" 售出票 "+tickets--);
                }
                else {
                    break;
                }
            }
        }
    }
}

Lock锁

可重用锁,显示定义同步锁,使用Lock对象。

使用ReentrantLock创建锁对象

ReentrantLock lock = new ReentrantLock();

开启锁

try{
	lock.lock();
}

关闭锁

finally {
	lock.unlock();
}

实例

import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket, "a").start();
        new Thread(buyTicket, "b").start();
        new Thread(buyTicket, "c").start();
    }
}

class BuyTicket implements Runnable {

    int ticketNums = 10;

	//使用ReentrantLock创建锁对象
    ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
            	//开启锁
                lock.lock();
                if (ticketNums > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + ticketNums--);
                } else {
                    break;
                }
            } finally {
            	//关闭锁
                lock.unlock();
            }
        }
    }
}

线程协调

一般在synchronized同步代码块里使用wait()、notify/notifyAll()方法。

wait()

  • 线程等待,会释放锁,释放资源,sleep不会。
  • wait()需要被try…catch包围。
this.wait();
this.wait(long timeout);

notify()

唤醒线程

this.notify();
this.notifyAll();	//唤醒所有等待的线程

生产者消费者问题

管程法

/*
测试生产者消费者模型-->利用缓冲区解决:管程法
生产者,消费者,产品,缓冲区
 */
public class Test {
    public static void main(String[] args) {
        SysContainer container = new SysContainer();
        new Productor(container).start();
        new Consumer(container).start();
    }
}

//生产者类
class Productor extends Thread {
    SysContainer container;

    public Productor(SysContainer container) {
        this.container = container;
    }

    //生产鸡!
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产了" + i + "只鸡");
            container.push(new Chicken(i));
        }
    }
}

//消费者类
class Consumer extends Thread {
    SysContainer container;

    public Consumer(SysContainer container) {
        this.container = container;
    }
    //消费者消费


    @Override
    public void run() {
        //消费
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了-->" + container.pop().id + "只鸡");
        }
    }
}

//产品类
class Chicken {
    int id;//生产编号

    public Chicken(int id) {
        this.id = id;
    }
}

class SysContainer {
    //设定容器大小
    Chicken[] chickens = new Chicken[9];
    //容器计数器
    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.notifyAll();
    }

    //消费者消费
    public synchronized Chicken pop() {
        //判断是否有鸡
        if (count == 0) {
            try {
                //没有鸡等待
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //有鸡就可以消费
        count--;
        Chicken chicken = chickens[count];
        //唤醒生产者生产
        this.notifyAll();
        return chicken;
    }
}

信号灯法

//解决生产者消费者问题方法2:信号灯法

public class TestPC2 {
    public static void main(String[] args) {
        TV tv =new TV();
        new Player(tv).start();
        new Watcher(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){
                this.tv.play("快乐大本营");
            }else{
                this.tv.play("斗鱼");
            }
        }
    }
}

//消费者:观众
class Watcher extends Thread{
    TV tv;

    public Watcher(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}

//产品:电视节目
class TV{
    //演员表演,观众等待 T
    //观众观看,演员等待 F
    String voice;
    boolean flag =true;
    public synchronized  void play(String voice){
        //观众观看,演员等待
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //若观众没看,演员表演
        System.out.println("演员表演了"+voice);
        //通知观众看
        this.notifyAll();
        this.voice=voice;
        this.flag=!this.flag;
    }
    //观看方法
    public synchronized  void watch(){
        //演员表演观众等待
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观看了:"+voice);
        //通知演员表演
        this.notifyAll();
        this.flag=!this.flag;
    }
}

线程池

  • 提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。
  • 可以避免频繁创建销毁、实现重复利用。
  • 提高响应速度(减少了创建新线程的时间)
  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  • 便于线程管理,如:
  1. corePoolSize:核心池的大小

  2. maximumPoolSize:最大线程数广

  3. keepAliveTime:线程没有任务时最多保持多长时间后会终止

ExecutorService

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    public static void main(String[] args) {
        //创建线程池,参数是线程数量,此处为10
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        //放入线程
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());

        //关闭线程池
        executorService.shutdown();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
		System.out.println(Thread.currentThread().getName());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值