线程补充

线程
线程间的等待唤醒机制
概述:
	Object 类中
  	void wait ()  在其他线程调用此对象的 notify () 方法或 notifyAll () 方法前,导致当前线程等待。
       
 	void wait (long timeout) 在其他线程调用此对象的 notify () 方法或 notifyAll () 方法,或者超过指定的时间量前,导致当前线程等待。
 
    void notify () 唤醒在此对象监视器上等待的单个线程。
        
    void notifyAll ()  唤醒在此对象监视器上等待的所有线程。 
    
案例:
	资源类:
    	package Demo6;

        public class BaoZi extends Thread {
            public String kouWei;
            public int jiaGe;
            //当flag为false时代表没有包子,为true时代表有包子。
            boolean flag =false;

            @Override
            public void run() {
                super.run();
            }
        }

	生产类:
		package Demo6;

        public class LaoBan extends Thread {
            int a=0;
            private BaoZi baozi;

            public LaoBan(BaoZi baozi) {
                this.baozi = baozi;
            }

            @Override
            public void run() {
                while (true){
                    synchronized (baozi){
                        if (baozi.flag){
                            try {
                                //进程休眠
                                baozi.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }else {
                            if (a%2==0){
                                baozi.kouWei="肉包子";
                                baozi.jiaGe=2;
                            }else {
                                baozi.kouWei="素包子";
                                baozi.jiaGe=1;
                            }
                             baozi.flag=true;
                            //唤醒进程
                             baozi.notify();
                             a++;
                        }
                    }
                }
            }
        }

	消费类:
		package Demo6;

        public class XiaoMing extends Thread {
            private BaoZi baozi;

            public XiaoMing(BaoZi baozi) {
                this.baozi = baozi;
            }

            @Override
            public void run() {
                while (true){
                    synchronized (baozi){
                        if (!baozi.flag){
                            try {
                                //进程休眠
                                baozi.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }else {
                            System.out.println(baozi.kouWei+"=="+baozi.jiaGe);
                            //唤醒进程
                            baozi.notify();
                            baozi.flag=false;
                        }
                    }
                }
            }
        }

	测试类:
		
        package Demo6;

        public class MyTest {
            public static void main(String[] args) {
                BaoZi baozi = new BaoZi();
                LaoBan ban = new LaoBan(baozi);
                XiaoMing ming = new XiaoMing(baozi);
                ban.start();
                ming.start();
            }
        }

结果:
	肉包子==2
	素包子==1
	肉包子==2
	素包子==1
	肉包子==2
	素包子==1
    ......
    Process finished with exit code -1

内存可见性问题
Java内存模型
	 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的。
	 Java内存模型规定了所有的变量都存储在主内存中。每条线程中还有自己的工作内存,
	 线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来)。
	 线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。
	 不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

	 Java中的可见性
	
	 对于可见性,Java提供了volatile关键字来保证可见性。
	 当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
	 而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,
	 当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。
	 另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,
	 并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。
	 
volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。
 	           相较于 synchronized 是一种较为轻量级的同步策略。
               
volatile 变量,用来确保将变量的更新操作通知到其他线程。
可以将 volatile 看做一个轻量级的锁,但是又与
锁有些不同:
 对于多线程,不是一种互斥关系
 不能保证变量状态的“原子性操作” 

案例:
	package org.westos.demo2;


    public class MyTest {
        public static void main(String[] args) {
            MyRunnable myRunnable = new MyRunnable();
            new Thread(myRunnable).start();
            while (true){
                    if (myRunnable.isFlag()) {
                        System.out.println("主线程进来了");
                        break;
                    }
            }
        }
    }


    class MyRunnable implements Runnable{
        //volatile 可以解决内存可见性问题。但是不能保证原子性的操作
      //注意  // boolean flag=false;
       volatile boolean flag=false;

        public boolean isFlag() {
            return flag;
        }

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

        @Override
        public void run() {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //修改flag 为true
            flag=true;
            System.out.println("子线程把flag的值改为了"+flag);
        }
    }boolean flag=false;没有被volatile修饰时,主线程读到的flag还是false,所以主线程进入不了判断语句。
结果:
	子线程把flag的值改为了trueboolean flag=false;volatile修饰时,子线程将flag的值改为true后,主内存中的flag立刻改为true,主线程读到的flag也就是true了。
结果:
	主线程进来了
	子线程把flag的值改为了true
	
	Process finished with exit code 0

CAS 算法
CAS 算法
 CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器
操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并
发访问。
 CAS 是一种无锁的非阻塞算法的实现。
 CAS 包含了 3 个操作数:
 需要读写的内存值 V
 进行比较的值 A
 拟写入的新值 B
 当且仅当 V 的值等于 A 时, CAS 通过原子方式用新值 B 来更新 V 的
   值,否则不会执行任何操作。
  jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronouse同步锁的一种乐观锁。JDK 5之前Java语言是靠synchronized关键字保证同步的,这是一种独占锁,也是是悲观锁。
  
 java.util.concurrent.atomic 包下提供了一些原子操作的常用类:
 AtomicBoolean 、 AtomicInteger 、 AtomicLong 、 AtomicReference
 AtomicIntegerArray 、 AtomicLongArray
 AtomicMarkableReference
 AtomicReferenceArray 

案例:
	package Demo7;

    public class Test1 {
        public static void main(String[] args) {
            MyRunnable myRunnable = new MyRunnable();
            //创建五个子进程
            for (int i = 0; i < 5; i++) {
                new Thread(myRunnable).start();
            }
        }

    }

    package Demo7;

    import java.util.concurrent.atomic.AtomicInteger;

    public class MyRunnable implements Runnable{
        AtomicInteger num= new AtomicInteger(1);
        @Override
        public void run() {
            while (true){
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getI());
            }
        }
        public int getI() {
            //getAndIncrement() 自加方法
            return num.getAndIncrement();
        }
    }


结果:
	1
    5
    4
    3
    2
    6
    7
    8
    10
    9
    11
    12
    13
    14
    15
    16
    20
    19
    17
    18
    21
    22
    23
    24
	.....
    
线程池的概述和使用
线程池概述
	程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。
	而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
	线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
	在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池

内置线程池的使用概述
	JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
		public static ExecutorService newCachedThreadPool():			根据任务的数量来创建线程对应的线程个数	
		public static ExecutorService newFixedThreadPool(int nThreads):	固定初始化几个线程
		public static ExecutorService newSingleThreadExecutor():		初始化一个线程的线程池
	这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
		Future<?> submit(Runnable task)
		<T> Future<T> submit(Callable<T> task)
	使用步骤:
		创建线程池对象
		创建Runnable实例
		提交Runnable实例
		关闭线程池
		
案例:
	package Demo7;

	import java.util.concurrent.*;
	
	public class Test1 {
	    public static void main(String[] args) throws ExecutionException, InterruptedException {
	        ExecutorService executorService = Executors.newCachedThreadPool();
	        MyRunnable myRunnable = new MyRunnable();
	        executorService.submit(myRunnable);
	        executorService.submit(new MyRunnable());
	        Future<Integer> future = executorService.submit(new MyCallable());
	        Integer integer=future.get();
	        System.out.println(integer);
	        executorService.shutdownNow();
	    }
	}
	
	
	package Demo7;
	
	
	public class MyRunnable implements Runnable{
	
	    @Override
	    public void run() {
	        System.out.println(Thread.currentThread().getName()+"线程执行了");
	    }
	}
	
	
	package Demo7;
	
	import java.util.concurrent.Callable;
	
	public class MyCallable implements Callable<Integer> {
	
	    @Override
	    public Integer call() throws Exception {
	        int num=100;
	        return num;
	    }
	}

结果:
	pool-1-thread-1线程执行了
	pool-1-thread-2线程执行了
	100
	
	Process finished with exit code 0

匿名内部类的方式实现多线程程序
案例演示
	匿名内部类的方式实现多线程程序
	
	new Thread(){代码…}.start();
	new Thread(new Runnable(){代码…}).start();
案例代码:
	package Demo7;

	public class MyTest2 {
	    public static void main(String[] args) {
	        new Thread(){
	            @Override
	            public void run() {
	                System.out.println("线程一执行了");
	            }
	        }.start();
	        new Thread() {
	            @Override
	            public void run() {
	                System.out.println("线程二执行了");
	            }
	        }.start();
	
	        new Thread(new Runnable() {
	            @Override
	            public void run() {
	                System.out.println("线程三执行了");
	            }
	        }).start();
	    }
	}

结果:
	线程一执行了
    线程二执行了
    线程三执行了

    Process finished with exit code 0

定时器的概述和使用
定时器概述
	定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。
	在Java中,可以通过Timer和TimerTask类来实现定义调度的功能。
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()
	开发中
		Quartz是一个完全由java编写的开源调度框架。

结果:
	package Demo7;
	
	import java.util.Timer;
	import java.util.TimerTask;
	
	public class MyTest3 {
	    public static void main(String[] args) {
	        Timer timer = new Timer();
	        timer.schedule(new MyTimer(timer),2000);
	    }
	}
	
	
	class MyTimer extends TimerTask{
	
	    private Timer timer;
	
	    public MyTimer(Timer timer) {
	
	        this.timer = timer;
	    }
	
	    @Override
	    public void run() {
	        System.out.println("定时器--演示");
	        timer.cancel();
	    }
	}
结果:
	//延时两秒后打印
	定时器--演示

	Process finished with exit code 0

    
案例2:定时删除文件
	package org.westos.demo8;

    import java.io.File;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Timer;
    import java.util.TimerTask;

    public class MyTest {
        public static void main(String[] args) throws ParseException {
            Timer timer = new Timer();
            DelFolderTask myTimerTask2 = new DelFolderTask(timer);
            String dateStr = "2020-08-21 14:53:00";
            timer.schedule(myTimerTask2, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr));
        }
    }
    class DelFolderTask extends TimerTask{

        private Timer timer;

        public DelFolderTask(Timer timer) {

            this.timer = timer;
        }

        @Override
        public void run() {
            File file = new File("demo");

            delFolder(file);
            timer.cancel();

        }

        private void delFolder(File file) {
            File[] files = file.listFiles();
            for (File f : files) {
                if (f.isFile()) {
                    f.delete();
                }else{
                    delFolder(f);
                }
            }
            file.delete();
        }
    }
线程的运行状态

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值