Java线程类也是一个object类,它的实例都继承自java.lang.Thread或其子类。编写线程运行时执行的代码有两种方式:一种是创建Thread子类的一个实例并重写run方法,第二种是创建类的时候实现Runnable接口。
1、创建Thread的子类
1.1、创建Thread子类的一个实例并重写run方法,run方法会在调用start()方法之后被执行。
public class MyThread extends Thread{
public void run() {
System.out.println("hello world");
}
}
执行
MyThread myThread = new MyThread();
myTread.start();
1.2、创建一个Thread的匿名子类,并启动
Thread mythread = new Thread(){
public void run() {
System.out.println("hello world");
}
};
mythread.start();
2、实现Runnable接口
2.1、创建实例实现Runnable接口
public class myRunnable implements Runnable{
public void run() {
System.out.println("hello world");
}
}
执行
Thread mythread = new Thread(new myRunnable());
mythread.start();
2.2、创建一个实现Runnable接口的匿名类
Runnable myRunnable = new Runnable() {
public void run() {
System.out.println("hello world");
}
};
3、竞态条件与临界区
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竞态条件发生的代码区称作临界区。
4、线程安全与共享资源
4.1、局部变量
局部变量存储在线程自己的栈中,因此,局部变量永远也不会被多个线程共享,是线程安全的。
4.2、局部的对象引用
对象的局部引用和基础类型的局部变量不太一样。尽管引用本身没有被共享,但引用所指的对象并没有存储在线程的栈内。所有的对象都存在共享堆中。如果在某个方法中创建的对象不会逃逸出(该方法,那么它就是线程安全的。实际上,哪怕将这个对象作为参数传给其它方法,只要别的线程获取不到这个对象,那它仍是线程安全的。
public void someMethod(){
LocalObject localObject = new LocalObject();
localObject.callMethod();
method2(localObject);
}
public void method2(LocalObject localObject){
localObject.setValue("value");
}
LocalObject对象没有被方法返回,也没有被传递给someMethod()方法外的对象。每个执行someMethod()的线程都会创建自己的LocalObject对象,并赋值给localObject引用。因此,这里的LocalObject是线程安全的。即使将LocalObject作为参数传给同一个类的其它方法或其它类的方法时,它仍然是线程安全的。当然,如果LocalObject通过某些方法被传给了别的线程,那它就不再是线程安全的了。
4.3、对象成员
对象成员存储在堆上。如果两个线程同时更新同一个对象的同一个成员,那这个代码就不是线程安全的。
public class NotThreadSafe{
StringBuilder builder = new StringBuilder();
public add(String text){
this.builder.append(text);
}
}
如果两个线程同时调用同一个NotThreadSafe实例上的add()方法,就会有竞态条件问题
NotThreadSafe sharedInstance = new NotThreadSafe();
new Thread(new MyRunnable(sharedInstance)).start();
new Thread(new MyRunnable(sharedInstance)).start();
public class MyRunnable implements Runnable{
NotThreadSafe instance = null;
public MyRunnable(NotThreadSafe instance){
this.instance = instance;
}
public void run(){
this.instance.add("some text");
}
}
改造为两个线程在不同的NotThreadSafe实例上调用add方法,变为线程安全的。
new Thread(new MyRunnable(new NotThreadSafe())).start();
new Thread(new MyRunnable(new NotThreadSafe())).start();