多线程使用

多线程使用

线程生命周期及状态

线程生命周期

常量 描述
NEW 尚未启动的线程处于此状态。
RUNNABLE 在Java虚拟机中执行的线程处于此状态。
BLOCKED 一个线程的线程状态阻塞等待监视器锁定。 处于阻塞状态的线程正在等待监视器锁定进入同步块/方法,或者在调用Object.wait后重新输入同步的块/方法。
WAITING 正在等待另一个线程执行特定动作的线程处于此状态。
TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
TERMINATED 已退出的线程处于此状态。

以上状态为Thread.State的常量

多线程的实现方式

简单实践

1、继承Thread类,重写run方法
	MyThread mt1 = new MyThread();
	mt1.start();
2、实现Runnable接口,实现run抽象方法
    MyRunnable mr=new MyRunnable();
	Thread t1= new Thread(mr);
	t1.start();
3、实现Callable接口,实现call抽象方法,与Runnable接口不同的是Callable可以返回线程的执行结果
    //方式1
    MyCallable mc=new MyCallable();
	FutureTask<String> ft=new FutureTask<>(mc);
	Thread t1=new Thread(ft);
	t1.start();
	//方式2
    MyCallable mc=new MyCallable();
    //创建执行服务
    ExecutorService ets = Executors.newFixedThreadPool(1);
    //提交执行
    Future<String> result=ets.submit(mc);
    //获取结果
    System.out.println(result.get());
    //关闭服务
    ets.shutdown();

多线程常用方法

方法 说明
void setName(String xxx) 设置线程的名称
String getName() 获取线程的名称
void setPriority(int xx) 设置线程的优先级,取值范围1-10,默认值为5
static void sleep(1000) 指定线程休眠,单位毫秒,不会释放当前已经拥有的锁
void join() 插队,等待该线程终止后其他线程才会执行, 阻塞其他线程
static void yield() 暂停当前正在执行的线程对象,但不阻塞,将线程转为就绪状态,让CPU重新调度,礼让不一定成功
Thread.currentThread() 获取当前运行的线程对象
void setDaemon(boolean) 守护线程,当普通线程结束后,守护线程也不会继续执行下去
boolean isAlive() 测试线程是否处于活动状态

静态代理

概念

静态代理模式总结:
1、真实对象和代理对象都要实现同一个接口
2、代理对象需要代理真实角色,所以需要真实角色
好处:
 代理对象可以做很多真实对象做不了的事情
 真实对象只需要专注自己的事情就好了
以下通过结婚案例说明,真实对象为人,代理对象为婚庆公司

代码实现

public class StaticProxy {
    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 target;

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

    @Override
    public void happyMarry() {
        before(); //结婚之前
        //结婚
        this.target.happyMarry();
        after();  //结婚之后
    }

    private void after() {
        System.out.println("结婚后布置现场!");
    }

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

代码实测

规范的停止线程方法

public class ThreadTest implements Runnable{
    /**
     * 定义是否停止线程
     */
    private boolean isStop = true;

    @Override
    public void run() {
        while(isStop){
            System.out.println(Thread.currentThread().getName()+"正在执行");
        }
    }
    /**
     * 停止线程
     */
    public void stopThread(){
        this.isStop = false;
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadTest tt = new ThreadTest();
        new Thread(tt,"兔子").start();
        for (int i = 0; i < 100; i++) {
            Thread.sleep(10);
            System.out.println(i);
            if(i == 95){
                System.out.println(i);
                //进行线程停止
                tt.stopThread();
            }
        }
    }
}

不安全的抢票案例

public class Ticket implements Runnable{
    public static void main(String[] args) {
        Ticket t =new Ticket();
        new Thread(t,"学生").start();
        new Thread(t,"票贩子").start();
        new Thread(t,"工人").start();
    }

    //定义20张票
    private int ticket = 20;

    @Override
    public void run() {
        while (true){
            try {
                if(!robTicket()){
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //抢票
    private boolean robTicket() throws InterruptedException {
        if(ticket<=0){
            return false; //停止线程
        }else{
            //使用sleep放大出现问题的概率
            Thread.sleep(30);
            ticket --;
            System.out.println(Thread.currentThread().getName()+"抢到了票,还剩下"+ticket+"张票!");
            return true;
        }
    }
}
//结果,因为操作了共享对象,所以造成了线程不安全,数据一致性缺失
票贩子抢到了票,还剩下0张票!
学生抢到了票,还剩下-1张票!
工人抢到了票,还剩下-1张票!

使用synchronized加锁解决并发不安全问题

方法加锁

//抢票
private synchronized boolean robTicket() throws InterruptedException {
    if(ticket<=0){
        return false; //停止线程
    }else{
        ticket --;
        System.out.println(Thread.currentThread().getName()+"抢到了票,还剩下"+ticket+"张票!");
        return true;
    }
}

代码块加锁==>代码块默认锁的this,可以自定义对象进行加锁

private  boolean robTicket() throws InterruptedException {
    synchronized (this) {
        if (ticket <= 0) {
            return false; //停止线程
        } else {
            ticket--;
            System.out.println(Thread.currentThread().getName() + "抢到了票,还剩下" + ticket + "张票!");
            return true;
        }
    }
}

自定义对象进行加锁

private final Object obj = new Object();
//抢票
private  boolean robTicket() throws InterruptedException {
    synchronized (obj) {
        if (ticket <= 0) {
            return false; //停止线程
        } else {
            ticket--;
            System.out.println(Thread.currentThread().getName() + "抢到了票,还剩下" + ticket + "张票!");
            return true;
        }
    }
}

使用lock加锁解决并发不安全问题

//定义lock锁对象
private final Lock lock = new ReentrantLock();
//抢票
private  boolean robTicket() throws InterruptedException {
    try {
        lock.lock();
        if (ticket <= 0) {
            return false; //停止线程
        } else {
            //使用sleep放大出现问题的概率
            Thread.yield();
            ticket--;
            System.out.println(Thread.currentThread().getName() + "抢到了票,还剩下" + ticket + "张票!");
            return true;
        }
    }finally {
        lock.unlock();  //一定要写在finally中,保证什么情况下都要释放锁
    }
}

死锁案例

public class TestSiSuo implements  Runnable{
    //使用static保证资源只有一份,所有的实例对象都是同样的锁
    static Chopsticks chopsticks = new Chopsticks();

    static Bowl bowl = new Bowl();

    private int id;

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

    @Override
    public void run() {
        while(true){
            //执行
            try {
                havingDinner();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 定义吃饭方法,需要先拿到筷子和碗才能吃饭
     */
    public void havingDinner() throws InterruptedException {
        if(id == 0){
            synchronized (chopsticks){
                System.out.println(Thread.currentThread().getName()+"拿到了筷子!");
                Thread.sleep(1000);
                synchronized (bowl){
                    System.out.println(Thread.currentThread().getName()+"拿到了碗!");
                }
            }
            System.out.println(Thread.currentThread().getName()+"开始吃饭了!");
        }else{
            synchronized (bowl){
                System.out.println(Thread.currentThread().getName()+"拿到了碗!");
                Thread.sleep(2000);
                synchronized (chopsticks){
                    System.out.println(Thread.currentThread().getName()+"拿到了筷子!");
                }
            }
            System.out.println(Thread.currentThread().getName()+"开始吃饭了!");
        }
    }


    public static void main(String[] args) {
        TestSiSuo ts =new TestSiSuo(0);
        TestSiSuo ts1 =new TestSiSuo(1);
        new Thread(ts,"小明").start();
        new Thread(ts1,"小红").start();
    }

}

class Chopsticks{
    //筷子锁
}

class Bowl{
    //碗锁
}

生产者和消费者案例(必须为同一把锁)

生产和消费方法在控制器内

package com.lwp.study.mythread;

/**
 * 测试生产者和消费者
 */
public class TestScAndXf {
    public static void main(String[] args) {
        //定义控制器
        Controller cl = new Controller();
        //生产者启动
        Producer pro = new Producer(cl);
        pro.setName("厨师");
        pro.start();
        //消费者启动
        Consumer cs = new Consumer(cl);
        cs.setName("吃货");
        cs.start();
    }
}

/**
 * 生产者对象
 */
class Producer  extends Thread{
    Controller cl;

    public Producer(Controller cl){
        this.cl = cl;
    }

    @Override
    public void run() {
        while(true){
            if(cl.count<=0){
                break;
            }
            //生产食物
            try {
                cl.production();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

/**
 * 消费者对象
 */
class Consumer extends Thread{
    Controller cl;

    public Consumer(Controller cl){
        this.cl = cl;
    }

    @Override
    public void run() {
        while(true){
            if(cl.count<=0){
                break;
            }
            //消费食物
            try {
                cl.eat();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

/**
 * 定义控制器
 */
class Controller{
    //定义信号提醒 true表示有吃的
    public boolean bool = true;
    //定义要生产几个
    public int count = 10;

    /**
     * 定义生产方法
     */
    public synchronized void production() throws InterruptedException {
        if(bool){
            //有吃的,等待
            this.wait();
        }else{
            //生产
            System.out.println(Thread.currentThread().getName()+"正在生产");
            bool = true;
            //生产完成提醒用户吃
            this.notifyAll();
        }
    }

    /**
     * 定义吃方法
     */
    public synchronized void eat() throws InterruptedException {
        if(bool){
            //有吃的,进行吃
            System.out.println(Thread.currentThread().getName()+"正在吃烤串,还需要吃"+count+"串");
            //吃完数量-1
            count-- ;
            bool = false;
            this.notifyAll();
        }else{
            //等待
            this.wait();
        }
    }
}

生产和消费方法在各自类中(使用控制器作为锁对象)

package com.lwp.study.mythread;

/**
 * 测试生产者和消费者
 */
public class TestScAndXf {
    public static void main(String[] args) {
        //定义控制器
        Controller cl = new Controller();
        //生产者启动
        Producer pro = new Producer(cl);
        pro.setName("厨师");
        pro.start();
        //消费者启动
        Consumer cs = new Consumer(cl);
        cs.setName("吃货");
        cs.start();
    }
}

/**
 * 生产者对象
 */
class Producer  extends Thread{
    Controller cl;

    public Producer(Controller cl){
        this.cl = cl;
    }

    @Override
    public void run() {
        while(true){
            if(cl.count<=0){
                break;
            }
            //生产食物
            try {
                production();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 定义生产方法
     */
    public void production() throws InterruptedException {
        synchronized (cl){
            if(cl.bool){
                //有吃的,等待
                cl.wait(); //唤醒通过锁对象等待
            }else{
                //生产
                System.out.println(Thread.currentThread().getName()+"正在生产");
                cl.bool = true;
                //生产完成提醒用户吃
                cl.notifyAll(); //唤醒通过锁对象唤醒
            }
        }
    }
}

/**
 * 消费者对象
 */
class Consumer extends Thread{


    Controller cl;

    public Consumer(Controller cl){
        this.cl = cl;
    }

    @Override
    public void run() {
        while(true){
            if(cl.count<=0){
                break;
            }
            //消费食物
            try {
                eat();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 定义吃方法
     */
    public void eat() throws InterruptedException {
        synchronized (cl){ //使用同一个控制器作为锁
            if(cl.bool){
                //有吃的,进行吃
                System.out.println(Thread.currentThread().getName()+"正在吃烤串,还需要吃"+cl.count+"串");
                //吃完数量-1
                cl.count-- ;
                cl.bool = false;
                cl.notifyAll();  //唤醒通过锁对象唤醒
            }else{
                //等待
                cl.wait();  //唤醒通过锁对象等待
            }
        }
    }
}

/**
 * 定义控制器
 */
class Controller{
    //定义信号提醒 true表示有吃的
    public boolean bool = true;
    //定义要生产几个
    public int count = 10;

}

线程池

package com.lwp.study.mythread;

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

public class ThreadPool {
    public static void main(String[] args) {
        //创建线程池,容量为3
        ExecutorService es = Executors.newFixedThreadPool(3);
        //运行
        es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
        es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
        es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
        //超出线程池容量的则在任务队列等待执行
        es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
        es.execute(new Thread( () -> System.out.println(Thread.currentThread().getName())));
        //关闭连接
        es.shutdown();
    }
}

posted @ 2021-07-23 00:23  幸运刘  阅读(42)  评论(0)    收藏  举报