Day7 多线程、锁

thread 线程毛线(真正执行的是线程,main线程,gc线程)

process 进程过程(系统分配进程,是一个单位,在进程里跑线程,保护伞,把所有线程放在里面)

单核cpu,同一时间只能做一件事情,如果做多个事情,线程之间切换很快,感觉不出来切换,看电影,声音、影像……一起执行

实现线程的三种方法:1、thread类  2、runable接口  3、callable接口

一、thread类继承runable接口

callable(了解一下,目前不重要)

第一种方法:继承Thread类

public class Demo01 extends Thread{//类要从这里继承,出错:下面再定义一个类,就只能static才能访问
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println("这是一个继承的线程"+i);
            }
        }
    }
    public static void main(String[] args) {
        Demo01 thread01 = new Demo01();
        thread01.start();//用的是start方法


        System.out.println("======================");
        for (int i = 0; i <2000 ; i++) {
            System.out.println("这是一个主线程"+i);
        }

    }
}

调用start()方法;先执行主线程,中间穿插执行继承的线程,两个线程交替执行。

总结:线程开启不一定立即执行,由cpu调度。

下载图片的流程思考:1、创建ThreadTest类,2、先导入一个Download类下载图片类包(传入url、filename),3、写Download类,4、ThreadTest类继承继承Thread类,5、(重点)重新run方法,执行DownLaod对象的downLaod方法(创建Download类对象,传入url,filename),《url,和filename哪里来呢?》,6、ThreadTest两个属性(rul,filename),7、重写构造方法(this.url=url;this.filename=filename)(6和7的方法是传参给run方法),8、然后创建主方法,在主方法中ThreadTest创建对象t1,t2(构造方法需要传参)传入(rul,filename),9、t1.start()    t2.start()执行。执行结果谁先下载完谁先执行完,不是先后,而是一起。

二、第二种方法:实现Runnable接口(推荐使用实现接口,而不是继承Thread类)

步骤和继承Thread类一样,只是最后要用静态代理new Thread(testRunable(类的对象)).start();

优势:方便灵活,方便同一对象被多个线程使用。

问题:下面的代码,多个线程操作同一个资源,会造成多个人拿同一张票

静态代理类

public class Demo02 implements Runnable{
    int ticktsNumber=100;

    @Override
    public void run() {
        while(ticktsNumber>0){
            System.out.println(Thread.currentThread().getName()+ticktsNumber+"张票");
            ticktsNumber--;
        }
    }

    public static void main(String[] args) {
        Demo02 demo02 = new Demo02();
        new Thread(demo02,"小明").start();
        new Thread(demo02,"小华").start();
        new Thread(demo02,"小天").start();
    }
}

线程的启用:多个线程操作同一个对象

三、静态代理类(婚庆公司的例子)

真实对象和代理对象都要实现同一个接口代理对象要代理真实角色 private String 

public class Demo03 {
    public static void main(String[] args) {
        WeddingConpany weddingConpany = new WeddingConpany(new You());
        weddingConpany.HappyMerry();

    }
}//注意上面是Demo03类,下面是其他类,如果卸载Demo03的括号里,出现需要将下面类转为static类才能调用的提示!!!出现过很多次这种情况了
    interface Merry{
        void HappyMerry();
    }
    class You implements Merry{

        @Override
        public void HappyMerry() {
            System.out.println("我要结婚啦!");
        }
    }
    class WeddingConpany implements Merry{
        private Merry target;
        public WeddingConpany(Merry target){//构造方法中传参,传入对象
            this.target=target;
        }

        @Override
        public void HappyMerry() {
            before();
            this.target.HappyMerry();//this这个类的target,执行方法
            after();

        }
    void before(){
        System.out.println(target+"我要结婚啦");
    }
    void after(){
        System.out.println(target+"结婚后");
    }
}

优点:代理对象可以做真实对象做不了的事情,真实对象专注做自己的事情

四、Lambda 函数式编程

一个抽象接口(interface),只有一个抽象方法(abstract)

1、外部类,写在类的{}外面

2、静态内部类  static修饰,写在类{}的里面

3、局部内部类,写在方法{}里面

4、匿名内部类:对象直接实现接口,取消类实现接口的环节(原来是类实现接口,对象实现类)

5、Lambda简化(其实是从上面,一步一步省略下来的,类或接口中只有唯一的一个方法才能省略,)

public class Demo04 {
    public static void main(String[] args) {
        ILove love=(String a)->{   //接口  对象 =(传参)
            System.out.println("i love you "+a);
        };
        love.iLove("小明");//对象调用接口方法
    };
    
}
interface ILove {  //接口定义方法
    void iLove(String a);
}

 五、网络延时  模拟网络延时的作用,放大问题的发生性,阻塞状态

1、sleep(ms)

重点记一句话:每个对象都有一把锁,sleep不会释放锁

public class Demo06 {
    public static void main(String[] args) throws InterruptedException {
        Date date = new Date(System.currentTimeMillis());
        while (true){
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH.mm.ss").format(date));
            date=new Date(System.currentTimeMillis());
        }
    }
}

2、yield  线程礼让, 礼让不一定成功,看cpu心情 

3、join 优先插队

public class Demo07 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <1000 ; i++) {
            System.out.println("vip来啦"+i);
        }
    }
//测试结果和教程不一样,每次join的位置不一样,而且是交叉跑,不是vip跑完再跑main
    public static void main(String[] args) throws InterruptedException {
        Demo07 demo07 = new Demo07();
        Thread thread = new Thread(demo07);
        thread.start();

        for (int i = 0; i <300 ; i++) {
            if(i==200){
                thread.join();
            }
            System.out.println("main线程"+i);
        }
    }
thread1.start();//线程结束后,不能再次开启,一次性的。除非再new对象
}

4、线程优先级priority

set priority(5)  ()括号里是常量,优先级,权重,默认优先级是5,最大是10,最小是1

5、守护线程  daemon

线程分为  用户线程 (main线程)、守护线程(gc(垃圾回收线程隐藏了))

注意:守护线程等待用户线程执行完毕,自动结束,虚拟机不用等待守护线程结束。

thread.setDaemon(trun);   默认用户线程都是flase

6、线程的同步 锁synchronized(隐式的)

队列+锁(排队上厕所,锁门)。弊端(有人3s解决完,还要等这个30min的人解决完才能进)

7、如何让线程变得安全(不安全的三个案例,买票,取钱)

8、同步方法、同步块

对方法加synchronized修饰,就会自动获得一把锁,变成同步方法

同步块

锁的是代码中变化的量,增删改。

JUC,java.util.concurrent包(并发包),

9、死锁:多个线程互相抱着对方需要的资源,不放手

10、Lock锁(显示的)ReentrantLock类实现Lock

public class Demo09 {
    public static void main(String[] args) {
        SellTicket sellTicket = new SellTicket();
        new Thread(sellTicket).start();
        new Thread(sellTicket).start();
        new Thread(sellTicket).start();
    }
}
class SellTicket implements Runnable {
    int ticket = 10;
private final ReentrantLock lock = new ReentrantLock();
    @Override
    public void  run() {

        while (true) {
            try {
                lock.lock();
                if (ticket>0){
                    Thread.sleep(1000);
                    System.out.println(ticket--);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {
                lock.unlock();
            }

        }
    }
}

六、线程协作

wait();等待

notify();唤醒

使用线程池:ExcutorService

 

你可能感兴趣的:(Day7 多线程、锁)