Java wait() volatile CAS算法 线程池 定时器

23.01 线程间的等待唤醒机制

  A:wait()
  		Object类中,void wait() 在其他线程调用此对象的 notify() 方法或
  		notifyAll() 方法前,导致当前线程等待。
  		
  		void wait(long timeout) 在其他线程调用此对象的 notify() 方法或
  		notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
  		
  		void notify() 唤醒在此对象监视器上等待的单个线程。
  		void notifyAll() 唤醒在此对象监视器上等待的所有线程。
/*
    条件
      1.生产者线程   SetThread
      2.消费者线程   GetThread
      3.资源  Student
      创建共享资源

    出现线程安全问题的条件
      1.是不是多线程环境
      2.是否多个线程共享资源
      3.是否有多条语句在操作这个共享资源

    要的效果是生产一个消费一个
    生产者:如果没有资源,就生产,如果有资源,就等着不生产,还得通知消费
    	   线程去消费
    消费者:如果有资源,就消费,如果没有资源就等着,还得通知生产线程去生产
*/

public class Demo01wait {
    public static void main(String[] args) {

        Student student = new Student();

        SetThread st = new SetThread(student);
        GetThread gt = new GetThread(student);

        st.start();
        gt.start();
    }
}

//资源
public class Student {
    public String name;
    public int age;

    //定义标记
    public boolean flag = false;    //false表示没有资源,true表示有资源
}

//生产线程
public class SetThread extends Thread{
    private Student student;

    int i = 0;
    public SetThread(Student student) {

        this.student = student;
    }

    @Override
    public void run() {
        while (true){
            synchronized (student){   //共用一把锁
                if (student.flag){
                    //作为生产线程,有资源就等待
                    try {
                        student.wait(); //线程一旦等待,就会释放锁,下
                        				//次如果被唤醒了,就从这里醒来
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (i%2==0){
                    student.name = "张三";
                    student.age = 23;
                }else {
                    student.name = "李四";
                    student.age = 24;
                }
                //通知消费线程去消费
                student.flag = true;    //修改标记
                student.notify();   //唤醒之后,线程也可以再次争抢
            }
            i++;
        }
    }
}

//消费线程
public class GetThread extends Thread{
    private Student student;

    public GetThread(Student student) {

        this.student = student;
    }

    @Override
    public void run() {
        while (true){
            synchronized (student){    //共用一把锁
                if (!student.flag){
                    //消费线程,如果没有资源,就等待
                    try {

                        /*
                            在调用Wait方法之前,线程必须获得该对象的对
                            象级别锁,即只能在同步方法或同步块中调用Wait
                            方法
                            wait() 方法导致当前线程处于等待状态,直到被
                            另一个线程调用 notify() 来唤醒
                        */

                        student.wait(); //线程一旦等待,就会释放锁,下
                        				//次如果被唤醒了,就从这里醒来
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //消费线程
                System.out.println(student.name + "====" + student.age);
                //通知生产线程,去生产
                student.flag = false;

                //notify() 需要在同步方法或同步块中调用,即在调用前,线
                //程也必须获得该对象的对象级别锁
                student.notify();   //唤醒之后,线程也可以再次争抢
            }
        }
    }
}

23.02 内存可见性问题 volatile

  A:volatile 关键字:
  		当多个线程进行操作共享数据时,可以保证内存中的数据可见。相较于
  		synchronized 是一种较为轻量级的同步策略。

  B:volatile 变量,用来确保将变量的更新操作通知到其他线程。可以将
  	 volatile 看做一个轻量级的锁,但是又与锁有些不同:
  	 	对于多线程,不是一种互斥关系
  	 	不能保证变量状态的 “原子性操作”。
public class Demo01Volatile {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();
        Thread thread = new Thread(mr);
        thread.start();

        /*
        while (true){
            //解决方案一
            synchronized (mr){
                if (mr.isFlag()){
                    System.out.println("进来了");
                    break;
                }
            }
        }
        */

        while (true){

            if (mr.isFlag()){
                System.out.println("进来了");
                break;
            }
        }
    }
}

class MyRunnable implements Runnable{

    /*
        volatile 当一个共享变量被volatile修饰时,
        它会保证修改的值会立即被更新到主存,当有其
        他线程需要读取时,它会去内存中读取新值

        volatile 可以保证内存可见性的问题,但是不能保证原子性的问题
     */

    volatile boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        //把这个flag的值改为true
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
        System.out.println(flag);
    }
}

23.03 CAS算法

  A:CAS算法
  		CAS(Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而
  		设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问

	 CAS是一种无锁的非阻塞算法的实现。
	 CAS包含了 3 个操作数:
	 	需要读写的内存值 V
	 	进行比较的值 A
	 	拟写入的新值 B

	 当且仅当 V 的值等于 A 时,CAS 通过原子方式用新值 B 来更新 V 的值,
	 否则不会执行任何操作。

	 java.util.concurrent.atomic 包下提供了一些原子操作的常用类:
	 	AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference
	 	AtomicIntegerArray、AtomicLongArray
	 	AtomicMarkableReference
	 	AtomicReferenceArray
public class Demo01Cas {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();
        for (int i = 0; i < 10; i++) {
            new Thread(mr).start();
        }
    }
}

class MyRunnable implements Runnable{

    /*
        我们可以通过CAS算法来解决原子性问题,相比较于使用synchronized来
        解决的
        CAS 比较并交换,他是我们CPU硬件支持的
    */

    //int i = 1;

    //Java 提供好的原子变量
    AtomicInteger i = new AtomicInteger(1);

    public AtomicInteger getI() {
        return i;
    }

    @Override
    public void run() {
        while (true){
            synchronized (MyRunnable.class){
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i.getAndIncrement());
            }
        }
    }
}

23.04 线程状态的常见执行情况

  A:新建,就绪,运行,冻结,死亡
  		新建:线程被创建出来
  		就绪:具有CPU的执行资格,但是不具有CPU的执行权
  		运行:具有CPU的执行资格,也具有CPU的执行权
  		阻塞:不具有CPU的执行资格,也不具有CPU的执行权
  		死亡:不具有CPU的执行资格,也不具有CPU的执行权

在这里插入图片描述

23.05 线程池

  A:线程池的意义
  		线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个
  		任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由
  		于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样
  		就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整
  		线程中的线程数目可以防止出现资源不足的情况。

  B:线程池的组成部分
  		至少应包含线程池管理器、工作线程、任务队列、任务接口等部分。其中
  		线程池管理器的作用是创建、销毁并管理线程池,将工作线程放入线程池
  		中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;
  		任务队列的作用是提供一种缓冲机制,将没有处理的任务放在任务队列中;
  		任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执
  		行完后线程池管理器至少有下列功能:创建线程池、销毁线程池、添加新
  		任务。

  C:内置线程的使用
  		public static ExecutorService newCachedThreadPool():
  				根据任务的数量来创建线程对应的线程个数

		public static ExecutorService newFixedThreadPool():
				固定初始化几个线程

		public static ExecutorService newSingleThreadExecutor():
				初始化一个线程的线程池

		这些方法的返回值是 ExecutorService 对象,该对象表示一个线程池,
		可以执行 Runnable 对象或者 Callable 对象代表的线程。

		Future<?> submit(Runnable task)
		<T> Future<T> submit(Callable<T> task)
public static void main(String[] args) {

        //通过工厂类,获取线程池对象
        //根据任务的数量来创建线程对应的线程个数
        ExecutorService es = Executors.newCachedThreadPool();

        //给线程池中提交任务
        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了111111");
            }
        });

        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了222222");
            }
        });

        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了333333");
            }
        });

        //关闭线程池
        es.shutdown();
    }
public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(3);

        Future<Integer> future = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("执行了");
                return 100;
            }
        });
        Integer integer = future.get();
        System.out.println(integer);
    }
public static void main(String[] args) {
        ExecutorService es = Executors.newSingleThreadExecutor();

        //给线程池中提交任务
        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了111111");
            }
        });

        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了222222");
            }
        });

        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行了333333");
            }
        });
    }
public static void main(String[] args) {
        //创建自己的线程池
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 10, 10L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1000), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        //提交任务
        tpe.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务执行完了");
            }
        });

        tpe.shutdown();
    }

23.06 定时器

  A:定时器概述
  		定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台
  		线程的方式执行。在Java中,可以通过 Timer 和 TimerTask 类来实现
  		定义调度的功能。

  B:Timer 和 TimerTask
  		Timer:
  			public Timer()
  			public void schedule(TimerTask task, long delay)
  			public void schedule(TimerTask task, long delay, long period)
  			public void schedule(TimerTask task, Date time)
  			public void schedule(TimerTask task, Date firstTime, long period)

		TimerTask:定时任务
			public abstract void run()
			public boolean cancel()
public class Demo01Timer {
    public static void main(String[] args) {
        Timer timer = new Timer();

        //类 TimerTask 由 Timer 安排为一次执行或重复执行的任务
        //等待多少毫秒之后,来执行这个定时任务
        MyTimerTask mtt = new MyTimerTask(timer);
        timer.schedule(mtt,1000*5);

        //取消定时任务
        //mtt.cancel();

        //取消定时器,终止此定时器,丢弃所有当前已安排的任务
        //timer.cancel();
    }
}

class MyTimerTask extends TimerTask{

    private Timer timer;

    public MyTimerTask(Timer timer) {

        this.timer = timer;
    }

    @Override
    public void run() {
        System.out.println("砰~~~爆炸了");

        //取消定时器
        timer.cancel();
    }
}
public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("砰~~~爆炸了");
            }
        },1000*2,1000); //第一次等待2秒执行,后面等待1秒执行异步任务
    }
public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();
        String dateStr = "2021-06-07 20:25:00";
        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("发送邮件");
            }
        },date);
    }
public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();
        String dateStr = "2021-06-07 20:28:00";
        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("发送邮件");
            }
        },date,1000);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值