JAVA多线程之Thread&&Runnable

来源:互联网 发布:windows系统启动 efi 编辑:程序博客网 时间:2024/05/29 13:21

看了个视频,嗯,记录下加深下理解。。。java实现多线程的两种方式:继承thread类,这种方式的缺陷就是java的单继承导致的;还有一种方式就是实现Runnable接口,这种方式避免了thread方式由于java单继承带来的缺陷。需要知道的是线程启动后会抢占CPU资源,如果当前new了一个线程,线程就会进入创建的状态,然后我们启动这个线程,thread.start(),这个时候这个线程就会处在就绪状态,如果当前能获取到CPU资源,然后就会处在运行状态,如果这个时候执行了sleep方法或者一些阻塞事件,会导致线程处于阻塞状态,然后sleep到一定时间后阻塞解除,会继续排队到就绪状态,继续等待当前释放CPU释放资源,如果run方法执行完毕的话,那么线程终止,自动销毁。这也是为什么不加synchronized的话会出现乱序的情况。因为你虽然进入了线程队列,但是当前cpu资源不一定是被你获得了,会被后来居上。也就是说你可能是先start()了,但是不一定能先run()。

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

使用继承thread的方式进行模拟卖票public class SoldTicketThread extends Thread {    private int ticket = 5;    private String name;    // 构造方法    public SoldTicketThread(String name) {        this.name = name;    }    public void run() {        while (ticket > 0) {            System.out.println(name + "卖出了一张票,剩余" + (--ticket) + "张票");        }    }    public static void main(String[] args) {        // 创建三个线程,模拟三个窗口卖票        SoldTicketThread wd1 = new SoldTicketThread("窗口一");        SoldTicketThread wd2 = new SoldTicketThread("窗口二");        SoldTicketThread wd3 = new SoldTicketThread("窗口三");        // 启动者三个线程,也就是窗口开始卖票        wd1.start();        wd2.start();        wd3.start();    }}运行结果:(这是因为我们创建了3个线程,每个线程都有5张票的资源,所以每个线程都卖自己的5张票,无法实现资源共享)窗口二卖出了一张票,剩余4张票窗口一卖出了一张票,剩余4张票窗口一卖出了一张票,剩余3张票窗口一卖出了一张票,剩余2张票窗口一卖出了一张票,剩余1张票窗口一卖出了一张票,剩余0张票窗口二卖出了一张票,剩余3张票窗口二卖出了一张票,剩余2张票窗口二卖出了一张票,剩余1张票窗口二卖出了一张票,剩余0张票窗口三卖出了一张票,剩余4张票窗口三卖出了一张票,剩余3张票窗口三卖出了一张票,剩余2张票窗口三卖出了一张票,剩余1张票窗口三卖出了一张票,剩余0张票
综合上面的结果,我们只能创建一个线程,拿到这5张票的共享资源public class SoldTicketThread implements Runnable {    private int ticket = 5;    public void run() {        while (ticket > 0) {            System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余" + (--ticket) + "张票");        }    }    public static void main(String[] args) {        // 创建一个实现了runnable接口的对象,拿到这5张票的资源        SoldTicketThread window = new SoldTicketThread();        //将这个资源类作为参数传递到3个线程中        Thread wd1=new Thread(window,"窗口一");        Thread wd2=new Thread(window,"窗口二");        Thread wd3=new Thread(window,"窗口三");        // 启动者三个线程,也就是窗口开始卖票        wd1.start();        wd2.start();        wd3.start();    }}运行结果:窗口一卖出了一张票,剩余4张票窗口一卖出了一张票,剩余2张票窗口一卖出了一张票,剩余1张票窗口二卖出了一张票,剩余3张票窗口一卖出了一张票,剩余0张票
如果你非要用继承thread的方式的话。。。public class SoldTicketThread extends Thread {    private int ticket = 5;    public void run() {        while (ticket > 0) {            System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余"                    + (--ticket) + "张票");        }    }    public static void main(String[] args) {        SoldTicketThread window = new SoldTicketThread();        Thread wd1 = new Thread(window, "窗口二");        Thread wd2 = new Thread(window, "窗口一");        Thread wd3 = new Thread(window, "窗口三");        wd1.start();        wd2.start();        wd3.start();    }}运行结果:窗口随机,卖票顺序随机窗口二卖出了一张票,剩余4张票窗口二卖出了一张票,剩余1张票窗口二卖出了一张票,剩余0张票窗口三卖出了一张票,剩余2张票窗口一卖出了一张票,剩余3张票

好想让这个卖票有个顺序肿么破。。。,使用synchronized锁住卖票操作的整个内容,使一次只卖一次票。给我们的资源加把锁

采用实现Runnable接口实现:public class SoldTicketThread implements Runnable {private int ticket = 5;private synchronized void sale() {if (ticket > 0) {System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余"+ (--ticket) + "张票");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}public void run() {while (ticket > 0) {sale();// 这里要确保进入卖票环节前就把资源锁住}}public static void main(String[] args) {SoldTicketThread window = new SoldTicketThread();Thread wd1 = new Thread(window, "窗口二");Thread wd2 = new Thread(window, "窗口一");Thread wd3 = new Thread(window, "窗口三");wd1.start();wd2.start();wd3.start();}}运行结果:(线程间(窗口)会进行抢占cpu资源,是随机的)窗口三卖出了一张票,剩余4张票窗口一卖出了一张票,剩余3张票窗口二卖出了一张票,剩余2张票窗口一卖出了一张票,剩余1张票窗口一卖出了一张票,剩余0张票
继承Thread类public class SoldTicketThread extends Thread {    private int ticket = 5;    public synchronized  void sale() {        if (ticket > 0) {            System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余"                    + (--ticket) + "张票");        }    }    public void run() {        while (ticket > 0) {            sale();        }    }    public static void main(String[] args) {        SoldTicketThread window = new SoldTicketThread();        Thread wd1 = new Thread(window, "窗口二");        Thread wd2 = new Thread(window, "窗口一");        Thread wd3 = new Thread(window, "窗口三");        wd1.start();        wd2.start();        wd3.start();    }}运行结果:(窗口会进行抢占cpu资源,是随机的)窗口三卖出了一张票,剩余4张票窗口一卖出了一张票,剩余3张票窗口一卖出了一张票,剩余2张票窗口一卖出了一张票,剩余1张票窗口一卖出了一张票,剩余0张票

总结:因为我们只是创建了一个拥有5张票的线程类的对象(有5张火车票),然后把这个对象作为参数传递给3个新创建的thread对象,所以共享了这5张火车票。然后我们再卖票操作加了synchronized操作,就可以实现按顺序卖票了。

需要记住的点是,我觉得初学者老师会觉得程序是从上到下执行的,很符合我们的逻辑,但是线程可以看做是并发操作,并不是说你先start了,你就会先run。
这里写图片描述

还要记录的点事守护线程的点。。。在Dos环境下,jstack可以查看当前运行java类的pid,然后输入 jstack -l pid可以查看到目前有什么守护线程。。。。
这里写图片描述

这里写图片描述

2 0
原创粉丝点击