线程的基本了解及操作

基本的概念

线程与进程直接的区别
首先,进程是系统资源分配的基本单位,一个进程对应一个程序。而线程是处理器任务调度和执行的基本单位。还存在资源开销、包含关系、内存分配、影响关系、执行过程等区别。

同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源相互独立。

而在java中线程之间方法区与堆内的数据是共享的,而栈中的资源是相互独立的。每一个单独的线程都会创建一个单独的栈空间。

也就是说假设启动十个线程,会有十个栈空间,每个栈与每个栈之间,互不干扰,各自执行各自的,这就是对线程并发

之所以会有多线程的机制,就是为了提高程序的执行效率。

但是一般在单核cpu的电脑上是不能真的进行多线程并发,只是进程之间切换的速度很快,如同早期的电影院使用的胶卷一般,人的感知中是连续不断的画面,但是实际中只是不停地切换画面而已。

线程的生命周期

创建->就绪->运行->阻塞->结束
在这里插入图片描述

注意:在java程序中使用了多线程机制后,main方法结束,意味着主线程结束,代表主栈空了,但是其他栈(线程)可能还在压栈弹栈。

线程的三种创建的方式

线程的创建方式有三种,但是我目前处于学生阶段第三种方法还是处于了解阶段

前两种方法都是通过继承Thread抽象类或实现Runable接口,然后通过在主方法中创建实例对象.start或.run的方式来创建线程。

主要区别就是通过继承Thread类的方式只能继承一个父类,相比于可以多个实现的接口来说,具有一定的局限性

第一种通过继承Thread抽像类以及重写run()方法创建线程

public class Thread_test02 {
    public static void main(String[] args) {
        mySecondThread me = new mySecondThread();
        me.start();//测试支线程
        myFirstThread me1 = new myFirstThread();
        me1.run();
        for (int i = 0; i < 200; i++) {
            System.out.println("我在测试主线程");//测试主线程
        }
    }
}

class mySecondThread extends Thread{
    public void run(){
        for (int i = 0; i < 200; i++) {
            System.out.println("我在测试不是主线程的线程");
        }
    }

}

另一种是通过实现Runable接口来实现线程的创建

package Thread;
//通过实现Runable接口创建线程
public class Thread_test01 {
    public static void main(String[] args) {
        myFirstThread me = new myFirstThread();
        me.run();
    }
}

class myFirstThread implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("这是我创建的第"+i+"个线程");
        }
    }
}

创建多个线程

package Thread;
//通过实现Runable接口创建多个线程
public class Thread_test03 {
    public static void main(String[] args) {
        Runable_test runable_test = new Runable_test();

        new Thread(runable_test,"第一个线程").start();
        new Thread(runable_test,"第二个线程").start();
        new Thread(runable_test,"第三个线程").start();
        //该创建方法为静态代理,只是传入对象然后实现Thread类

    }
}
class Runable_test implements Runnable{

    @Override
    public void run() {
        System.out.println("创建的线程");
    }
}

拓展

在Runable接口中我们打开其源码,我们可以看到接口只有一个run()方法,我们可以通过匿名内部类或者lamdbm语句的形式来创建线程

package java.lang;

@FunctionalInterface
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

而通过Thread抽象类的部分源码我们可以看出,我们可以通过设定其中的priority在设置线程优先级,daemon来设置是否为守护线程,用过name来设置线程名字。还有就是该类的类对象是通过contextClassLoader来加载的。

    private volatile String name;
    private int            priority;
    private Thread         threadQ;
    private long           eetop;

    /* Whether or not to single_step this thread. */
    private boolean     single_step;

    /* Whether or not the thread is a daemon thread. */
    private boolean     daemon = false;

    /* JVM state */
    private boolean     stillborn = false;

    /* What will be run. */
    private Runnable target;

    /* The group of this thread */
    private ThreadGroup group;

    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;

线程的启动

线程的启动有两种方法一个是run()方法与start()方法,但是这两种方法有很大差别。

首先,run()方法不会启动的线程,不会创建一个新的线程。run方法是单线程的。

而start()方法是开辟一个新的栈内存(栈空间),然后该方法就结束了,并且该线程就启动成功了,之后线程自动调用run方法来运行该线程

(run方法在分支栈的栈底部,start方法在主栈的栈底部,run方法与start方法是平等的

线程的阻塞

线程的阻塞主要使用的是jion()方法该方法也成为插队方法

package Thread;

public class Thread_testjion  implements  Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 255; i++) {
            System.out.println("线程中的贵族降临!");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread_testjion ts = new Thread_testjion();
        Thread thread = new Thread(ts);
        thread.start();

        for (int i = 0; i < 299; i++) {
            if(i==200){
                thread.join();//在主线程运行至200是,支线程插队,而此时主线程就会被阻塞
            }
            System.out.println("我是主线程!");
        }
    }
}

线程的等待

线程的等待主要使用的是sleep()方法

package Thread;
//有此例子了解sleep方法,并且初步了解线程同步问题
public class Thread_test04 {
    public static void main(String[] args) {
        ticket t = new ticket();
        new Thread(t,"它").start();
        new Thread(t,"他").start();
        new Thread(t,"她").start();


    }
}

class ticket implements  Runnable{
    private  int ticketNum = 10;

    @Override
    public void run() {
        while (true){
            if (ticketNum<=0){
                break;
            }
            try {
                Thread.sleep(1000);//睡眠等待1s,如果注释改行代码会使得全部票一下被全部人抢完
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了第"+ticketNum--+"票");
        }
    }

}

线程优先级

线程的优先级为1到10级。线程的优先级也高代表该线程进入内存并且获得cpu的计算资源的机会就越大,但是不一定优先处理,只是一个机会的概念,其次java中线程创建的默认优先级为5。我们也可以通过setPriorty()方法来设定优先级。

package Thread;

public class Thread_testPriority implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("现在是"+Thread.currentThread().getName()+"在跑");
        }
    }

    public static void main(String[] args) {
        Thread_testPriority myPriorty = new Thread_testPriority();
        Thread t1 = new Thread(myPriorty);
        Thread t2 = new Thread(myPriorty);
        Thread t3 = new Thread(myPriorty);
        Thread t4 = new Thread(myPriorty);
        Thread t5 = new Thread(myPriorty);

        t1.start();

        t2.setPriority(5);
        t2.start();

        t3.setPriority(1);
        t3.start();

        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();

        t5.setPriority(4);
        t5.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程默认优先级为5");
        }

    }
}

线程的停止

我们在线程还没有执行完之前停止线程我们有很多方法,有destroy方法但是该方法已经被舍弃了,因为该方法会产生很多的问题。我们一般停止线程的方法是设立一个标志位,当标志位为真时该线程继续执行,该标志位为假时该线程停止。

package Thread;
//学会使用通过信号的方式停止线程
public class Thread_teststop {
}

class testStop implements Runnable{

    @Override
    public void run() {
        int i = 0 ;
        while (flag){
            System.out.println(i++);
        }
    }

    boolean flag = true;//标志位

    public void stop() {//中止线程的方法
        this.flag=false;
    }

    public static void main(String[] args) {
        testStop ts = new testStop();

        new Thread(ts).start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("main"+i);
            if (i==800){
                ts.stop();
                System.out.println("支线程停止了");
            }
        }
    }
}

线程的礼让

sleep方法与yield方法的区别:sleep()方法会给其他线程运行的机会,不考虑其他线程的优先级,因此会给较低优先级线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。

当线程执行了sleep(long millis)方法,将转到阻塞状态,参数millis指定睡眠时间;当线程执行了yield()方法,将转到就绪状态。

线程的礼让是线程在运行态时将线程重新回归到就绪态,就是主动让出cpu的计算资源,但是线程的礼让不一定成功,因为线程在礼让后还是可以去抢占cpu资源的,所以礼让的结果不一定成功。

package Thread;

//yield方法不一定成功,由cpu调度
public class Thread_testyield implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            System.out.println("这是" + Thread.currentThread().getName() + "在跑");
            Thread.yield();//礼让不一定成功
        }
    }
    public static void main(String[] args) {
        Thread_testyield y = new Thread_testyield();
        new Thread(y, "礼貌的男人").start();
        new Thread(y, "礼貌的女人").start();
        new Thread(y, "礼貌的小孩").start();
        new Thread(y, "礼貌的老人").start();
    }
}

线程的状态

线程的状态对应的是线程的五种不同的生命周期

package Thread;

public class Thread_teststate implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 28; i++) {
            System.out.println("现在在跑支线程");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread_teststate tt = new Thread_teststate();
        Thread thread = new Thread(tt);
        System.out.println(thread.getState());
        thread.start();
        System.out.println(thread.getState());
        while (thread.getState()!=Thread.State.TERMINATED){
            thread.sleep(100);
            System.out.println(thread.getState());
        }


    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值