Java中关于线程提供了Thread类和Runnable接口,二者都包含run()方法来执行线程,常用的方法列举如下:
线程的创建和停止
可以通过继承Thread类来新建一个线程类,也可以通过将类实现Runnable接口来新建。线程拥有name属性来标识,可以调用setName()方法来设置,也可以在新建Thread对象时调用构造方法传入字符串为线程命名。Thread类内可以使用getName()获取线程的名字,实现Runnable则没有此方法,可以使用Thread.currentThread().getName()来得到名字。无论是继承Thread类还是实现Runnable接口,都需要重载run()方法,在run()中定义线程所进行的操作。在创建线程对象之后,通过调用start()方法就会开始执行run()中的内容。
线程的停止不能使用stop()或者interrupt(),而应该在子线程中设置标志来控制线程的执行。例如在子线程内通过volatile变量来控制子线程的循环,如果需要停止,可以在主进程中访问该变量,将其设为false来结束循环。这样子进程可以继续执行之后的内容,进行清理工作等,然后结束子进程。
如下所示在主进程首先创建两个低级别线程thread1、thread2,通过start()启动后交替执行,每执行一次就会通过yield()让出处理器,再次进行竞争。之后通过runFlag手动停止两个低级别线程,然后创建并执行高级别线程highThread。最后等待highThread执行结束后,结束主进程。
//低级进程类
public class LowThread implements Runnable {//通过实现接口来新建线程类
volatile boolean runFlag = true; //通过标记来控制循环的执行
@Override
public void run() {
int count = 1;
String threadName=Thread.currentThread().getName();
while (runFlag) {
System.out.println(threadName + "线程循环次数:" + count++);
Thread.yield(); //每循环一次让出处理器,重新和其他线程竞争处理器
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(threadName+"执行结束");
}
}
//高级进程类
public class HighThread extends Thread { //通过继承Thread类来新建一个线程类
public void run() {
System.out.println(getName() + "执行!"); //Thread类内通过getName()获取线程名
}
}
//主进程
public class RunThread {
public static void main(String[] args) throws InterruptedException {
LowThread thread1Run=new LowThread(); //新建RUnnable对象
Thread thread1=new Thread(thread1Run,"线程1"); //使用Runnable对象初始化Thread
thread1.start(); //线程启动,自动执行run()方法
LowThread thread2Run=new LowThread();
Thread thread2=new Thread(thread2Run,"线程2");
thread2.start();
Thread.sleep(50); //主线程休眠让出处理器,让thread1和2使用处理器执行
System.out.println("高级线程切入");
thread1Run.runFlag=false; //在线程外通过volatile变量控制低级线程停止
thread2Run.runFlag=false;
HighThread highThread=new HighThread();
highThread.setName("高级别线程");
highThread.start();
highThread.join(); //让其他线程等待直到高级线程执行结束,否则会先执行主线程,输出下一句
System.out.println("主线程执行结束");
}
}
运行情况如下所示,可以看到在高级进程首先结束,子进程在主进程之后停止,可以做相关清理等工作。
线程互斥和同步
Java通过新建一个Object锁来控制对于临界资源的访问。通过synchronized关键字来控制同步,在进入临界区时首先进行条件判断,如果满足则进入,否则将线程放入等待区wait set,之后执行临界区代码,执行结束后调用notify()/notifyAll()通知其他进程再次进行资源争夺。
private final Object lockObj = new Object();
synchronized (lockObj) {
//进入临界区的条件判断
while (条件) {
try {
//条件不满足, 将当前线程放入Wait Set
lockObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//执行临界区代码
func();
//唤醒所有在lockObj对象上等待的线程
lockObj.notifyAll();
}