线程(一)---线程基本状态、创建线程方式、守护线程

写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!  

线程的状态及转换:

对 wait()、sleep()、notifyAll() 的理解:

这三个方法是定义在Object类里的方法。

wait(): 使持有该对象的线程把该对象的控制权(锁)交出,然后处于等待状态。

notify(): 通知某个正在等待这个对象控制权的线程恢复运行。

notifyAll(): 通知所有等待这个对象控制权的线程恢复运行。

任何时候对象的控制权只能被一个线程拥有,在执行这三个方法时,首先应保证当前运行的线程获取了该对象的控制权,否则就会报java.lang.IllegalMonitorStateException异常。所以注意:这三个方法的使用需要在同步方法(代码块、实例)中使用,否则会出现问题。

对 wait()、sleep()、yield() 的理解:

wait():线程等待,交出对象控制权,即释放对象锁

sleep():线程休眠,一定时间后继续执行,并没有释放锁

yield():放弃执行,进入可执行状态,下次获取到cpu时间片可再执行,也没有释放持有的锁

拓展:

wait(long timeout): 

官网有这么一段话:

当调用wait()方法时,使当前线程等待,直到另一个线程调用此对象的notify或notifyAll方法,或等待的时间已过,才会继续执行,准确的说notify也行并不能唤醒这个等待的线程,因为可能有多个线程都在等待这个对象的控制权,notify只会随机唤醒一个线程。

wait(0)同wait一样,线程只能是被唤醒后, 才能再次获取锁执行wait后续代码。

 

创建线程的三种方式

1):继承Thread  重写run方法  调用Thread实现类的start()方法启动线程

public class MyThread extends Thread {
    public void run(){
        System.out.println("111");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

2):实现Runnable 重写run方法  执行线程需要丢入runnable接口的实现类 调用start方法

public class MyThread implements Runnable {
    public void run(){
        System.out.println("111");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
}

3):实现Callable接口 重写call()方法 通过创建执行服务来执行目标线程

public class MyThread implements Callable {
    @Override
    public Object call() throws Exception {
        return "111";
    }

    public static void main(String[] args) throws Exception{
       MyThread thread1 = new MyThread();
        ExecutorService service = Executors.newCachedThreadPool();
        Future future = service.submit(thread1);
        System.out.println(future.get());
        service.shutdown();
    }
}

继承和实现的方式创建线程的区别也是显而易见的,1)实现的方式可以避免java中单继承的限制,2)适合多个线程去处理一个资源。3)而相比于Runnable方式,实现Callable有返回值 ,Runnable方式没有返回值。

通过代码理解下它们的区别,看一下下面的例子:

public class TestThread {
    public static void main(String[] args) {
        new Test1("A").start();
        new Test1("B").start();
        new Test1("C").start();
    }
}


class Test1 extends Thread{
    private int ticket = 5;

    public Test1(String s) {
        this.setName(s);
    }

    @Override
    public void run() {
        while (true){
            buy();
        }
    }
    private void buy(){
        if(ticket <= 0){
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"拿到"+ticket--);
    }
}

执行结果:

 

 如上:我启动了三个线程ABC去买票,最终的执行结果其实是这三个线程分别去买了5张票。

上面说到,实现Runnable接口的方式适合多个线程去处理一个资源,看下下面的例子:

public class RunnableTest {
    public static void main(String[] args) {
        Buy buy = new Buy();
        new Thread(buy,"A").start();
        new Thread(buy,"B").start();
        new Thread(buy,"C").start();
    }



}
class Buy implements Runnable{
    private int ticket = 10;
    @Override
    public  void run() {
        while (true){
            buy();
        }
    }
    private synchronized void buy(){
        if(ticket <= 0){
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"拿到"+ticket--);
    }
}

 执行结果:

守护线程

线程其实分为用户线程和守护线程,想让一个线程成为守护线程只要通过线程的.setDaemon(true);方法设置即可。

虚拟机在运行的时候,必须保证用户线程执行完毕,并且不用等待守护线程执行完毕。可以理解为守护线程其实就是默默守护我们用户线程执行的线程,例如垃圾回收gc线程,我们甚至不用管他,只要咱们的用户线程执行完(main线程执行完),守护线程也会自动停止。通过下面的例子看一下:

public class TestThread {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread thread = new Thread(god);
        thread.setDaemon(true);
        thread.start();
        Thread thread1 = new Thread(you);
        thread1.start();
    }
}

class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("a");
        }
    }
}

class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
        System.out.println("一切结束了");
    }
}

先贴一下执行结果:

如上:如果不是设置为守护线程,thread线程应该会一直执行下去,控制台一直打印a,但是我们看到,线程thread在thread1执行完后也停止了。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值