您的位置:首页 > 编程语言 > Java开发

Java基础_Thread(一)

2016-06-28 17:59 344 查看
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("由 "+t
c3b4
his.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方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: