Java守护线程

Java守护线程

守护线程是为其他线程服务的线程,在所守护线程执行完毕之后就会退出

TurtleThread2 t2就是main的守护线程

package test01;


class TurtleThread2 extends Thread{
    public TurtleThread2(String name) {
        super(name);
    }


    public void run(){
        long timeStart=System.currentTimeMillis();

        System.out.println(Thread.currentThread().getName() + "起跑了");
        for (int i = 1; i <= 1000; i++) {

            try {
                System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");
                Thread.sleep(700);
            } catch (InterruptedException e) {
                System.out.println("触发");
            }
            if(Thread.currentThread().isInterrupted()){
                System.out.println("检测到已经中断");
            }
        }
        System.out.println(Thread.currentThread().getName() + "到终点了");
        long timeEnd=System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName()+"用时"+(timeEnd-timeStart));
    }
}

public class Main {
    public static void main(String[] args) throws Exception {

        long timeStart=System.currentTimeMillis();
        TurtleThread2 t2=new TurtleThread2("乌龟2");
        t2.setDaemon(true);//设为守护线程,需要在start()之前
        //main线程结束 守护进程就会结束
        t2.start();


        System.out.println(Thread.currentThread().getName() + "起跑了");
        for (int i = 1; i <= 10; i++) {
            try {
                System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");
                Thread.sleep(700);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "到终点了");
        long timeEnd=System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName()+"用时"+(timeEnd-timeStart));

    }
}

线程安全与线程不安全

测试类Main.java

package test01;

public class Main {
    public static int count=0;


    public static void main(String[] args) throws InterruptedException {
        int ticket=10;
        TicketWindow window=new TicketWindow(ticket);
        Thread thread1=new Thread(window);
        thread1.setName("窗体一");
        Thread thread2=new Thread(window);
        thread2.setName("窗体二");
        Thread thread3=new Thread(window);
        thread3.setName("窗体三");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

线程安全

package test01;


public class TicketWindow implements Runnable {

    private int ticket = 10;
    private Object obj = new Object();

    public TicketWindow(int ticket) {
        this.ticket = ticket;
    }

    @Override
    public void run() {
        while (true) {
            //对变量加锁,线程安全
            synchronized (obj) {//同步代码块,只有一个线程访问ticket
                if (ticket > 0) {
                    try {
                        Thread.sleep(1000);
                        ticket -= 1;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName()+"卖票 1 张,余票 "+ticket+" ,时间戳"+System.currentTimeMillis());
                }else{
                    return;
                }
            }

        }
    }
}

输出:

窗体一卖票 1 张,余票 9 ,时间戳1610983793485
窗体一卖票 1 张,余票 8 ,时间戳1610983794558
窗体三卖票 1 张,余票 7 ,时间戳1610983795573
窗体二卖票 1 张,余票 6 ,时间戳1610983796587
窗体三卖票 1 张,余票 5 ,时间戳1610983797598
窗体一卖票 1 张,余票 4 ,时间戳1610983798611
窗体三卖票 1 张,余票 3 ,时间戳1610983799624
窗体二卖票 1 张,余票 2 ,时间戳1610983800633
窗体三卖票 1 张,余票 1 ,时间戳1610983801648
窗体三卖票 1 张,余票 0 ,时间戳1610983802658

一次打印一行,余票逐一递减,有时会出现只有一个窗口售票的情况,很有可能是因为自己的cpu运行状态和我不同导致的,可以尝试增加票量,private int ticket = 100;

线程不安全

package test01;


public class TicketWindow implements Runnable {

    private int ticket = 10;
    private Object obj = new Object();

    public TicketWindow(int ticket) {
        this.ticket = ticket;
    }

    @Override
    public void run() {
        while (true) {
            //线程不安全
            if (ticket > 0) {//满足卖票条件ticket一定>0
                try {
                    Thread.sleep(1000);//如果不是线程安全,在sleep的时候ticket可能会被其他线程改变
                    ticket -= 1;//这里ticket就不一定>0了
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName()+"卖票 1 张,余票 "+ticket+" ,时间戳"+System.currentTimeMillis());
            }else{
                return;
            }

        }
    }
}

输出:

窗体二卖票 1 张,余票 8 ,时间戳1610983544023
窗体一卖票 1 张,余票 7 ,时间戳1610983544024
窗体三卖票 1 张,余票 8 ,时间戳1610983544023
窗体二卖票 1 张,余票 6 ,时间戳1610983545099
窗体三卖票 1 张,余票 5 ,时间戳1610983545100
窗体一卖票 1 张,余票 5 ,时间戳1610983545100
窗体二卖票 1 张,余票 2 ,时间戳1610983546114
窗体一卖票 1 张,余票 3 ,时间戳1610983546114
窗体三卖票 1 张,余票 3 ,时间戳1610983546114
窗体二卖票 1 张,余票 1 ,时间戳1610983547129
窗体三卖票 1 张,余票 0 ,时间戳1610983547129
窗体一卖票 1 张,余票 -1 ,时间戳1610983547129

大概是每次(三个打印时间很接近)打印三行,可以看出余票显示混乱,而且有时还出现负数

上面采用同步代码块实现线程安全,下面采用同步方法实现同样效果

package test01;


public class TicketWindow implements Runnable {

    private int ticket = 10;
    private Object obj = new Object();

    public TicketWindow(int ticket) {
        this.ticket = ticket;
    }

    synchronized void sell(){
        if (ticket > 0) {//满足卖票条件ticket一定>0
            try {
                Thread.sleep(1000);//如果不是线程安全,在sleep的时候ticket可能会被其他线程改变
                ticket -= 1;//这里ticket就不一定>0了
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"卖票 1 张,余票 "+ticket+" ,时间戳"+System.currentTimeMillis());
        }
    }

    @Override
    public void run() {
        while (true){
            sell();
            if(!(ticket>0)){
                return;
            }
        }
    }
}

还可以通过手动加锁解锁实现线程安全

package test01;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TicketWindow implements Runnable {

    private int ticket = 100;
    private Object obj = new Object();
    Lock lock=new ReentrantLock(true);

    public TicketWindow(int ticket) {
        this.ticket = ticket;
    }

    void sell() {
        if (ticket > 0) {
            try {
                Thread.sleep(1000);
                ticket -= 1;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "卖票 1 张,余票 " + ticket + " ,时间戳" + System.currentTimeMillis());
        }
    }

    @Override
    public void run() {
        while (true) {
            lock.lock();//上锁
            sell();
            lock.unlock();//解锁
            if (!(ticket > 0)) {
                return;
            }
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值