第六周总结内容

本文详细介绍了Java中多线程的创建方式,包括实现Runnable接口、线程池的使用及其参数、线程安全与同步锁synchronized的应用。还探讨了静态和动态代理模式,以及生产者消费者问题和线程间的通信。此外,还讲解了Java的IO流操作、序列化和递归算法,最后涉及了面试中常见的线程相关问题。
摘要由CSDN通过智能技术生成

多线程

多线程的创建方式2—实现Runnable接口

1)自定义一个类,实现Runnable接口
2)实现接口里的run方法  完成耗时操作
3)在main用户线程中创建当前类的实例---资源对象
4)创建线程类Thread对象,然后将3)的资源对象 作为参数传递,启动线程

代码实现

//真实角色
public class MyRunnable  implements Runnable{
    @Override
    public void run() {
        for(int x = 0 ; x < 200 ; x++){
            //Thread类的静态方法public static Thread currentThread()
            //返回当前正在执行的线程对象的引用
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }
}


//测试类
public class ThreadDemo {

    public static void main(String[] args) {

        //创建当前这个类对象  "资源类"
        MyRunnable my = new MyRunnable() ;

        //创建两个线程,同时可以给线程设置名称
        //public Thread(Runnable target,String name)
        //Thread类--->代理角色
        Thread t1  = new Thread(my,"t1") ;
        Thread t2  = new Thread(my,"t2") ;

        //分别启动线程
        t1.start();
        t2.start();
    }
}

多线程创建方式1和创建方式2的区别

1)从代码具体的实现上说
	方式1:使用的继承,继承关系具有局限性,继承了一个类的同时,将这个类的所有方法都可以拿过来,公共的方法都可以访问!(其他的方法可能不用)
	方式2:使用的接口,本身只有一个run方法(面向接口编程)
2)内存角度考虑:是否能够体现“数据共享”的概念
	方式1:三个栈指向三个堆,体现不出数据共享
	方式2:能够体现数据共享,三个线程在同时操作同一个资源
3)方式2--面向接口编程的方式,而且使用到了代理模式之“静态代理”

多线程的创建方式3:线程池

什么是线程池

线程池:
	会创建一些固定的可重复使用的线程数,会在线程池中.循环利用
当某些线程使用完毕,不会被释放掉,而是归还链接池中,等待下一次再去利用
成本比普通创建线程方式要大!
	ThreadFactory:线程工厂,创建线程
	线程池可以重复利用初始化的线程数量
Java.util.concurrent.Executors 工厂类
public static ExecutorService newFixedThreadPool(int nThreads)
	创建固定的可重复的线程数的线程池
	
java.util.concurrent ExecutorService ----->接口的具体实现类 public class ThreadPoolExecutor
       <T> Future<T> submit(Callable<T> task):提交异步任务,返回值就是异步任务计算的结果;
      上面这个的返回值Future :异步计算的结果---如果现在只是看多个线程是否能够并发的去强转CPU执行权,并没有返回结果
      这个返回值可以不用返回!
      Callable:接口---->异步任务的执行  类似于 之前Runnable接口
 
       void shutdown():关闭线程池
代码实现线程池创建线程
public class ThreadPoolDemo {

    public static void main(String[] args) {
        //创建一个线程池
        //Executors
        //public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService threadPool = Executors.newFixedThreadPool(2);//创建两个线程-->放在线程池中

        //执行异步任务
        //<T> Future<T> submit(Callable<T> task):提交异步任务,返回值就是异步任务计算的结果;
        threadPool.submit(new MyCallable()); //创建异步执行任务
        threadPool.submit(new MyCallable())   ;


        //void shutdown():关闭线程池
        //关闭线程池
        threadPool.shutdown();
    }
}



//异步任务
public class MyCallable  implements Callable {
    @Override
    public Object call() throws Exception {
        //1-100之间的数据,两个线程都需要进来,能否出现并发执行
        for(int x = 1; x <=100 ; x++){
            System.out.println(Thread.currentThread().getName()+":"+x) ;
        }
        return null;
    }
}

线程池的七大参数

	1)corePoolSize 核心线程数量
	2)maxmumPoolSize最大核心线程数
	3)workQueue阻塞队列
	4)keepAliveTime生存时间
	5)TimeUnit unit时间计量点位
	6)handler拒绝策略:当线程数已经到最大核心线程池并且同事workQueue里面队列到达满的状态,线程池会启用拒绝策略
	7)ThreadFactory:创建线程的工厂----创建默认的线程池的名称以及后面的序列编号/同事创建线程
		

线程池的特点

线程使用完毕,归还到线程池中,可重复利用,降低资源的消耗
提高线程的维护,还是借助线程池的参数

java设计模式 结构型设计 代理模式

代理设计模式
	代理核心思想:
			真实角色专注自己的事情(开发中,针对自己的业务)
			代理角色帮助真实完成一件事情

静态代理

静态代理
			代理角色和真实角色要实现同一个接口
静态代理例题:婚庆公司
interface  Mary{
    void mary() ;
}
//每一个人都需要结婚
//真实角色
class You implements  Mary{
    @Override
    public void mary() {
        System.out.println("要结婚了很开心...");
    }
}
//代理角色---->婚庆公司
class WeddingCompany implements  Mary{

    //声明接口
    private Mary mary ;
    //有一个有参构造方法
    public WeddingCompany(Mary mary){ //需要接口子实现类 You
        this.mary = mary ;
    }

    @Override
    public void mary() {
        System.out.println("结婚之前,混穷公司布置婚礼现场!");
        if(mary!=null){
            mary.mary(); //核心的方法(真实角色要实现自己的事情)
        }
        System.out.println("婚礼现场完成之后,给婚庆公司付尾款!");
    }
}

//测试类
public class StaticProxyDemo {
    public static void main(String[] args) {
        //创建You类对象(多态/自己new 自己)
        You you = new You() ;
        you.mary();
        System.out.println("------------------使用静态代理-------------------------");

        //创建资源类对---->真实角色
        You you2 = new You() ;
        //创建代理角色---->婚庆公司
        WeddingCompany wc = new WeddingCompany(you2) ;
        wc.mary();
    }
}
电影院买票方式一代码实现
//继承关系
public class SellTicketThread  extends  Thread{

    //100张票
    private static int tickets = 100 ;

    //t1,t2,t3都要并发执行
    @Override
    public void run() {
        //模拟一直有票
        while (true){

            //模拟真实场景,线程睡眠
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //如果tickets>0
            if(tickets>0){
                System.out.println(getName()+"正在出售第"+(tickets--)+"张票");
            }
        }

    }
}


//测试类
public class SellTicketTest {
    public static void main(String[] args) {

        //创建三个线程类对象
        SellTicketThread st1 = new SellTicketThread() ;
        SellTicketThread st2 = new SellTicketThread() ;
        SellTicketThread st3 = new SellTicketThread() ;
        //线程名称
        st1.setName("窗口1") ;
        st2.setName("窗口2") ;
        st3.setName("窗口3") ;

        //启动线程
        st1.start();
        st2.start();
        st3.start();
    }
}
方式2实现电影院卖票
 /*  方式2实现
 
   当加入延迟效果,可能出现
   1)同票出现  --------------->线程的执行的过程---原子性操作!(针对最简单,最基本的操作++,--)
   2)可能出现负票!
     线程不安全!*/


//真实角色
public class SellTicket implements Runnable {
    //100张票
    private static int tickets = 100 ;

    @Override
    public void run() {


        //模拟一直有票
        while (true){
            //t1,t2,,t3
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(tickets>0){
                System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");

            }/*else{
                break;
            }*/
        }
        /**
         * 出现同票/负票--->线程不安全!
         *     变量-- ---->原子性操作(线程的执行具有随机性)
         *              1) 窗口1进来了    记录原始值---100 ---->100-1 =99
         *              2)窗口3进来了    在打印99的时候,同时窗口2也进来了,也直接使用这个原始值 99,然后--
         */
    }
}



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


        //创建资源类对象:真实角色
        SellTicket st = new SellTicket() ;
        //创建三个线程,代表三个窗口
        Thread t1 = new Thread(st,"窗口1") ;
        Thread t2 = new Thread(st,"窗口2") ;
        Thread t3 = new Thread(st,"窗口3") ;

        //启动线程
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}


动态代理

动态代理
		jdk动态代理
		只要有一个接口  反射的方式完成陈队接口的对象的创建
		cglib动态代理--基于类就可以

解决线程安全

	 校验多线程安全问题的标准 (使用标准来看多线程环境是否存在问题,以及解决方案)
       1)是否是多线程环境   --->是
       2)是否有共享数据    ---> 是存在的
       3)是否有多条语句对共享数据操作
                               tickets票:多条语句同时操作
        将3)多条语句多共享数据的操作使用同步代码块包起来---解决线程安全问题
         synchronized(锁对象){
             多条语句对共享数据操作
         }
 

同步锁synchronized

如果方法的第一句话就是
synchronized(锁对象){
	将多条语句多共享数据包裹起来
}
可以将synchronized提到方法声明上

     锁对象:可以是任意Java类对象,但是多个线程必须使用的同一个锁对象,否则"锁不住"!
 

同步方法:将synchronized声明到方法上

 什么是同步方法(非静态)?如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上
           权限修饰符  synchronized 返回值类型 方法名(参数列表){
               ...
           }
      非静态同步方法:锁对象:this---代表类对象的地址值引用
      如果是静态的同步方法,锁对象---->当前类名.class(字节码文件对象)

同步机制

同步机制
		多个线程在并发的使用公共变量,保证同步,某个线程在当前这个数据进行持有的时候
		,其他线程是不能访问的--通过synchorized同步代码块就可以解决线程安全问题
	1)需要将多条语句对共享数据进行操作使用同步代码快包裹起来
	2)同步机制里面的监视器,俗称“锁”,可以市人医java类对象,多个线程必须使用同一个监视器
	或者使用同步方法--锁对象 this
	静态的同步方法--->锁对象 当前类名.class  字节码文件
	
	同步机制:
		包括wait()和notify()

锁对象:可以是任意java类对象

//定义两个锁对象
public class MyLock {
    public static Object objA = new Object() ;
    public static Object objB = new Object() ;
}

//资源类

public class DieLock  implements Runnable{
    private boolean flag ; //boolen类型
    public DieLock(boolean flag){
        this.flag = flag ;
    }

    @Override
    public void run() {
        if(flag){
            //同步代码块
            synchronized (MyLock.objA){
                System.out.println("if...ObjA...");
                synchronized (MyLock.objB){
                    System.out.println("if...ObjB...");
                }
            }
        }else {
            synchronized (MyLock.objB){
                    System.out.println("else...ObjB...");
                synchronized (MyLock.objA){
                    System.out.println("else...ObjA...");
                }
            }
        }
    }
}


//测试类
public class DieLockDemo {
    public static void main(String[] args) {

        //创建资源类对象
        DieLock dl1 = new DieLock(true) ;
        DieLock dl2 = new DieLock(false) ;

        //创建两个线程
        Thread t1 = new Thread(dl1) ;
        Thread t2 = new Thread(dl2) ;

        //启动线程
        t1.start() ;
        t2.start() ;
    }
}
代码实现电影院卖票(加锁):
class Demo{}
public class SellTicket implements Runnable {
    //100张票
    private static int tickets = 100 ;
    private Object obj = new Object() ; //实例变量
    private Demo demo  = new Demo() ;

    private int  x = 0 ;
    @Override
    public void run() {


        //模拟一直有票
        while (true){
            //t1,t2,,t3
            try {
                Thread.sleep(1000);//模拟网络延迟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // synchronized(锁对象){
            // *            多条语句对共享数据操作
            // *        }
            //t1/t2/t3
            //synchronized (new Object()){ //锁对象  ,每一个线程进来使用自己的锁对象!
            //t1如果先抢占cpu执行权了
            if(x % 2==0){
               // synchronized (demo){ //t1,t2,t3这个三个线程使用的同一个锁
               //synchronized (this){ //t1,t2,t3这个三个线程使用的同一个锁
               synchronized(SellTicket.class){
                    if(tickets>0){
                        System.out.println(Thread.currentThread().getName()+
             "正在出售第"+(tickets--)+"张票");
                    }
                }
            }else{
                //x%2 !=0
               /* synchronized (demo){ //t1,t2,t3这个三个线程使用的同一个锁
                    if(tickets>0){
                        System.out.println(Thread.currentThread().getName()+
                                "正在出售第"+(tickets--)+"张票");
                    }
                }*/
                SellTicket.sellTicket();
            }
            x++;
        }
    }

    //定义一个方法sellTicket

    /**
     * 什么是同步方法(非静态)?如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上
     *            权限修饰符  synchronized 返回值类型 方法名(参数列表){
     *                ...
     *            }
     */
   /* public synchronized void sellTicket(){  //锁对象是谁?  --->this
          //t1,t2,t3这个三个线程使用的同一个锁
            if(tickets>0){
                System.out.println(Thread.currentThread().getName()+
                        "正在出售第"+(tickets--)+"张票");
            }

    }*/
    public static synchronized void sellTicket(){//静态的同步方法的锁跟类相关---->当期类的字节码文件对象  类名.class
        //t1,t2,t3这个三个线程使用的同一个锁
        if(tickets>0){
            System.out.println(Thread.currentThread().getName()+
                    "正在出售第"+(tickets--)+"张票");
        }

    }

}



//测试类
public class SellTicketTest {
    public static void main(String[] args) {


        //创建资源类对象:真实角色
        SellTicket st = new SellTicket() ;

        //创建三个线程,代表三个窗口
        Thread t1 = new Thread(st,"窗口1") ;
        Thread t2 = new Thread(st,"窗口2") ;
        Thread t3 = new Thread(st,"窗口3") ;

        //启动线程
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

线程安全—可能出现死锁

  使用synchronized解决线程安全问题,安全问题解决了,效率低,可能死锁现象
 
  死锁:
       两个线程出现了一种互相等待的情况,A线程等待B线程释放锁,B线程等待A线程释放锁,造成死锁现象!
       举例
               中国人 和美国人吃饭
               一双筷子    一把刀 和一个叉子
 
               现在
                   中国人                 美国人
                   一根筷子/一个叉子          一把刀和一根筷子
 
    解决死锁问题--->线程之间的通信必须使用的同一个资源!  (生产者和消费者模式思想)

消费这生产者模式思想---信号灯法

模拟生产者和消费者思想

模拟生成者和消费者思想
 
       Student类:学生数据(消费者和生成者需要使用的数据)
       SetData类:生成资源类
       GetDate类:消费者资源类
 
       按照上面格式:生成者产生数据,消费者使用数据
       问题1)null---0,生产者和消费者资源类中使用的资源不是同一个对象
 
       改进:生产者和消费者资源类中使用的资源是同一个了
       但是现在生产者不断的产生数据,消费者不断地使用
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值