Java基础_Thread(一)

1:继承Thread的方式
继承Thread
实现runnable接口
实现runnable接口更容易达到多继承的特性


线程的状态图
线程的状态


2:在多线程技术中,代码是顺序执行的吗? 不是

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread");
    }
}
public class Run {

    public static void main(String[] args) {
        MyThread mythread = new MyThread();
        mythread.start();
        System.out.println("运行结束!");
    }
}

程序输出:
运行结束!
MyThread

解释:在我们的Run类里面,其有一个主线程,当调用子线程的start方法的时候,即通知“线程规划器”此线程已经准备就绪,等待调用线程的run方法,这个过程其实就是让系统安排一个时间来调用Thread的run方法,也就是启动线程,使其具有异步执行效果。这里就带出一个线程的特性:线程具有随机特性。

问题一:这里会先打印MyThead,再打印 运行结束!吗? 不会
解释:Run类是主线程,其是向下执行的,子线程MyThread具有随机性,需要系统调用。举个例子

public class Run {

    public static void main(String[] args) {
        for(int i = 0 ; i < 5000 ; i++){
            System.out.println("i=" + i);
        }
        System.out.println("上面的循环执行完了");
        for(int j = 0 ; j < 5000 ; j++){
            System.out.println("j=" + j);
        }
        System.out.println("执行完毕");
    }
}

这里就需要等待第一个循环做完,才会打印“上面的循环执行完了”,然后等待第二个线程执行完,才会打印“执行完毕”

问题二:调用线程的start方法就是线程的执行顺序吗? 不是
解释:调用start方法只是让线程进入就绪状态,还需要系统分配时间片给线程让其进入运行状态,因此调用start方法的顺序不是线程的执行顺序

问题三:多次调用线程的start方法是否可以? 不可以
会抛出异常“IllegalThreadStateException”


3:实例变量与线程安全
自定义线程类中的实例变量针对其他线程可以有共享与不共享之分。
例如:

public class MyThread extends Thread {

    private int count=5;

    @Override
    synchronized public void run() {
        super.run();
        while(count > 0){
            count--;
            System.out.println("由 "+this.currentThread().getName()+" 计算,count="+count);
        }
    }
}

实现非共享的方式:

MyThread mythreadA = new MyThread("A");
MyThread mythreadB = new MyThread("B");
MyThread mythreadB = new MyThread("C");
mythreadA.start();
mythreadB.start();
mythreadC.start();

此时每个线程都有各自的count变量,自己减少自己的count变量的值


实现共享的方式:

MyThread mythreadA = new MyThread();
Thread a = new Thread(mythreadA,"A");
Thread b = new Thread(mythreadB,"B");
Thread b = new Thread(mythreadC,"C");
a.start();
b.start();
c.start();

此时每一个线程共享一个count。但是这样的方式就产生了“非线程安全”的问题。
非线程安全是指:多个线程对同一个对象的同一个实例变量进行操作时,会出现值被更改,值不同步的问题。


解决“非线程安全”问题的方法之一:添加synchronize关键字
原因:多线程访问一个带有synchronize关键字的方法的时候,以排队的方式进行处理,当一个线程调用synchronize方法时,会尝试去拿这把锁,如果能够拿到,则可以执行,否则这个线程就会不断尝试拿这把锁,直到能够拿到为止。而且是多个线程同时去抢这把锁。


1):synchronize方法
也就是同步方法,它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。

当考虑阻塞时,一定要注意哪个对象正被用于锁定:1、调用同一个对象中非静态同步方法的线程将彼此阻塞。如果是不同对象,则每个线程有自己的对象的锁,线程间彼此互不干预。 2、调用同一个类中的静态同步方法的线程将彼此阻塞,它们都是锁定在相同的Class对象上。 3、静态同步方法和非静态同步方法将永远不会彼此阻塞,因为静态方法锁定在Class对象上,非静态方法锁定在该类的对象上。 4、对于同步代码块,要看清楚什么对象已经用于锁定(synchronized后面括号的内容)。在同一个对象上进行同步的线程将彼此阻塞,在不同对象上锁定的线程将永远不会彼此阻塞。


特例:println方法和i–表达式

public class MyThread extends Thread {

    private int i = 5;

    @Override
    public void run() {
        System.out.println("i=" + (i--) + " threadName="
                + Thread.currentThread().getName());
    }
}

println()方法内部是同步的,即其内部实现了synchronize效果。但是上面的方法依旧会代码“非线程安全”问题,因为i–的操作是在进入println()方法前发生,因此有发生非线程安全的问题的概率。


4: 实例化Thread分析,线程的名字,Thread=0的来历

public class MyThread extends Thread {
    @Override
    public void run() {
    }
}
MyThread myT = new MyThread ();
Thread t1 = new Thread(myT);

在这个过程中会调用Thread的构造函数

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }

因此就产生了Thread-0,Thread-1…等


5: Thread.currentThread().getName() 和 this.getName()的分析

public class CountOperate extends Thread {

    public CountOperate() {
        System.out.println("CountOperate---begin");
        System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
        System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
        System.out.println("this.getName()=" + this.getName());
        System.out.println("this.isAlive()=" + this.isAlive());
        System.out.println("CountOperate---end");
    }

    @Override
    public void run() {
        System.out.println("run---begin");
        System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
        System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
        System.out.println("this.getName()=" + this.getName());
        System.out.println("this.isAlive()=" + this.isAlive());
        System.out.println("run---end");
    }
}

输出为:

CountOperate---begin
Thread.currentThread().getName()=main
Thread.currentThread().isAlive()=true
this.getName()=Thread-0
this.isAlive()=false
CountOperate---end
run---begin
Thread.currentThread().getName()=A
Thread.currentThread().isAlive()=true
this.getName()=Thread-0
this.isAlive()=false
run---end

分析如下:Thread.currentThread()表示执行该处代码的线程的引用,而this表示当前类的引用。
因此在run方法中的this.getName()表示执行CountOperate类的getName方法,但是CountOperate没有getName方法,则其是执行Thread的getName方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值