多线程笔记2

多线程基础

线程的状态
  • 创建状态

在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时它已经有了相应的内存空间和其他资源,但还处于不可运行状态。新建一个线程对象可采用Thread 类的构造方法来实现,例如 “Thread thread=new Thread()”。

  • 就绪状态

新建线程对象后,调用该线程的 start() 方法就可以启动线程。当线程启动时,线程进入就绪状态。此时,线程将进入线程队列排队,等待 CPU 服务,这表明它已经具备了运行条件。

  • 运行状态

当就绪状态被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run() 方法。run() 方法定义该线程的操作和功能。

  • 阻塞状态

一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入/输出操作,会让 CPU 暂时中止自己的执行,进入阻塞状态。在可执行状态下,如果调用sleep(),suspend(),wait() 等方法,线程都将进入阻塞状态,发生阻塞时线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。

  • 死亡状态

线程调用 stop() 方法时或 run() 方法执行结束后,即处于死亡状态。处于死亡状态的线程不具有继续运行的能力

线程的优先级

在 Java 的线程操作中,所有的线程在运行前都会保持在就绪状态,那么此时,哪个线程的优先级高,哪个线程就有可能会先被执行。(不是一定被先执行!)

class MyThread implements Runnable{ // 实现Runnable接口
    public void run(){  // 覆写run()方法
        for(int i=0;i<5;i++){
            try{
                Thread.sleep(500) ; // 线程休眠
            }catch(InterruptedException e){
            }
            System.out.println(Thread.currentThread().getName()
                    + "运行,i = " + i) ;  // 取得当前线程的名字
        }
    }
};
public class ThreadPriorityDemo{
    public static void main(String args[]){
        Thread t1 = new Thread(new MyThread(),"线程A") ;  
        Thread t2 = new Thread(new MyThread(),"线程B") ;  	
        Thread t3 = new Thread(new MyThread(),"线程C") ; 
        t1.setPriority(Thread.MIN_PRIORITY) ;   // 优先级最低
        t2.setPriority(Thread.MAX_PRIORITY) ;   // 优先级最高
        t3.setPriority(Thread.NORM_PRIORITY) ;  // 优先级最中等
        t1.start() ;    
        t2.start() ;   
        t3.start() ;    
    }
};
同步及死锁

同步代码块

public class Demo02 {
    public static void main(String[] args) {
        //线程不安全
        //解决方案1、同步代码块
        //任何对象都可以添加锁的标记
        //格式: sychronized(锁对象){
        //
        //      }
        Object o = new Object();
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable {
        //票数
        private int count = 10;
        private Object o = new Object();

        @Override
        public void run() {
            while (true) {
                synchronized (o) {
                    if (count > 0) {
                        //卖票
                        System.out.println("正在准备卖票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
                    }else {
                        break;
                    }
                }
            }
        }
    }
}

同步方法

public class Demo03 {
    public static void main(String[] args) {
        //线程不安全
        //解决方案2、同步方法
        //任何对象都可以添加锁的标记
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable {
        //票数
        private int count = 10;
        @Override
        public void run() {
            while (true) {
                boolean flag = sale();
                if (!flag){
                    break;
                }
            }
        }

        public synchronized boolean sale(){
            if (count > 0) {
                //卖票
                System.out.println("正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
                return true;
            }
            return false;
        }
    }
}

显示锁

public class Demo04 {
    public static void main(String[] args) {
        //线程不安全
        //同步代码块 和 同步方法都属于隐式锁
        //解决方案3、显示锁 Lock 子类 ReentrantLock
        //任何对象都可以添加锁的标记
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable {
        //票数
        private int count = 10;
        //显示锁 lock : fair参数为true就是公平锁
        private Lock lock = new ReentrantLock(true);

        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    if (count > 0) {
                        //卖票
                        System.out.println("正在准备卖票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
                    } else {
                        break;
                    }
                } finally {
                    lock.unlock();
                }
                lock.unlock();
            }
        }
    }
}

线程死锁

​ 所谓死锁,就是两个线程都在等待对方先完成,造成程序的停滞,一般程序的死锁都是在程序运行时出现的。

避免方法:

​ 在任何一个产生锁的方法里,不要在调用其他可能产生锁的方法

public class Demo05 {
    public static void main(String[] args) {
        //线程死锁
        //在任何一个产生锁的方法里,不要在调用其他可能产生锁的方法
        Culprit c = new Culprit();
        Police p = new Police();
        new MyThread(c,p).start();
        c.say(p);
    }
    static class MyThread extends Thread{
        private Culprit c;
        private Police p;
        public MyThread(Culprit c,Police p){
            this.c = c;
            this.p = p;
        }
        @Override
        public void run() {
            p.say(c);
        }
    }
    //罪犯
    static class Culprit{
        public synchronized void say(Police p){
            System.out.println("罪犯:你放了我,我放了人质");
            p.fun();
        }
        public synchronized void fun(){
            System.out.println("罪犯被放走了,罪犯也放了人质");
        }
    }
    //警察
    static class Police{
        public synchronized void say(Culprit c){
            System.out.println("警察:你放了人质,我放过你");
            c.fun();
        }
        public synchronized void fun(){
            System.out.println("人质获救了,罪犯被放走了");
        }
    }
}
线程池 Executors

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程 就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容 器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。

线程池的好处
  • 降低资源消耗。
  • 提高响应速度。
  • 提高线程的可管理性
Java中的四种线程池 . ExecutorService

1.缓存线程池

/**
 * 缓存线程池.
 * (长度无限制)
 * 执行流程:
 * 1. 判断线程池是否存在空闲线程
 * 2. 存在则使用
 * 3. 不存在,则创建线程 并放入线程池, 然后使用
 */
public class Demo08 {
    public static void main(String[] args) {
        //创建缓存线程池
        ExecutorService service = Executors.newCachedThreadPool();
        //指挥线程池执行新的任务
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}
2. 定长线程池
/**
 * 定长线程池.
 * (长度是指定的数值)
 * 执行流程:
 3. 单线程线程池
 4. 周期性任务定长线程池
 * 1. 判断线程池是否存在空闲线程
 * 2. 存在则使用
 * 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
 * 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
 */

public class Demo09 {
    public static void main(String[] args) {
        //定长线程池
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
    }
}
3. 单线程线程池
效果与定长线程池 创建时传入数值1 效果一致.
/**
* 单线程线程池.
* 执行流程:
* 1. 判断线程池 的那个线程 是否空闲
* 2. 空闲则使用
* 4. 不空闲,则等待 池中的单个线程空闲后 使用
*/
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
	@Override
	public void run() {
		System.out.println("线程的名称:"+Thread.currentThread().getName());
	}
});
service.execute(new Runnable() {
	@Override
	public void run() {
		System.out.println("线程的名称:"+Thread.currentThread().getName());
	}
});
4. 周期性任务定长线程池
public class Demo11 {
    public static void main(String[] args) {
        //周期定长线程池
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
        /**
         * 1.   定时执行一次
         * 参数1. 定时执行任务
         * 参数2. 时长数字
         * 参数3. 时长数字的时间单位,TimeUnit常量指定

        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("锄禾日当午");
            }
        },5, TimeUnit.SECONDS); */
        /**
         * 周期性执行任务
         * 参数1. 任务
         * 参数2. 延迟时长数字(第一次执行在什么时间以后)
         * 参数3. 周期时长数字(每隔多久执行一次)
         * 参数4. 时长数字的单位
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("汗滴禾下土");
            }
        },5,1,TimeUnit.SECONDS);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值