Java多线程:Java多线程基础
创建线程的方法
1.创建直接创建Thread的子类,重写run()方法;
class MyThread extends Thread { @Override public void run() { System.out.println("This is my thread"); }}public class Test { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); }}
2.创建一个线程执行类实现Runnable接口,在这个执行类里实现Runnable的run()方法,创建该执行类的对象后,用此执行类对象初始化新线程,启动新线程时即执行这个执行对象的run()方法;
class MyRunnable implements Runnable { @Override public void run() { System.out.println("This is my thread"); }}public class Test { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); }}
3.通过线程工厂用工厂模式来创建新线程,新建工厂类继承ThreadFactory类重写newThread()方法,通过指定实现了Runnable接口的执行类来创建与之对应的线程;
public class ThreadFactoryDemo { public static void main(String[] args) { ThreadFactory factory = new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) { // TODO Auto-generated method stub return new Thread(r);} }; factory.newThread(new Runnable() {@Overridepublic void run() { System.out.println("in runnable.");} }).start(); }}
注意:只有调用Thread类的Start方法,才能真正地在一个独立的线程中执行代码,直接调用Thread类的run方法,并不能启动一个新的线程,代码是在调用者线程中执行的。
线程究竟执行哪个run()方法
当线程同时具有可执行对象实现的run()方法和线程重写的run()方法时,启动线程时究竟执行哪个run()方法呢?
结果是如果只定义了可执行对象的run()方法则执行这个run()方法,如果只重写了线程的run()方法则执行这个run()方法,如果两个方法都有则执行线程重写的run()方法。
public class Test { public static void main(String[] args) { Thread thread = new Thread(new Runnable() {@Overridepublic void run() { System.out.println("Runnable.run()");} }) {@Overridepublic void run() { // TODO Auto-generated method stub System.out.println("Thread.run()");} }; thread.start(); }}
线程的休眠
使用Thread类的sleep()方法或者使用TimeUnit的相关方法来休眠线程,休眠的意思是资源仍被占用,但是线程保留原来的状态没有活动;
public class ThreadSleep { public static void main(String[] args) { Thread th = new Thread(new Runnable() {public void run() { for (int i = 0; i < 10; i++) { try {// Thread.sleep(500);TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace(); } }} }); th.start(); }}
线程中断
线程中断的意思是线程停止当前的运行状态让出资源结束生命周期,当外界想要一个线程中断时需要调用它的interrupted()方法,调用后不是直接就可以中断这个线程,而是将线程的interrupted标记位赋为1,如果要线程要响应这个中断则定期需要检查这个标记,检查到被中断标记后自己退出执行状态。
public class ThreadInterruptDemo { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread() {@Overridepublic void run() { while (true) { System.out.println("running"); if (isInterrupted())return; }} }; thread.start(); Thread.sleep(2000); thread.interrupt(); }}
线程定时任务
线程要实现定时任务的话可以使用Runnable的实现类TimerTask,此类需要重写run()方法以完成具体需要进行的定时任务。然后由定时器Timer来调度,使用Timer的schedle()方法相当于启动这个定时任务线程。
public class TimerTaskDemo { public static void main(String[] args) { TimerTask task = new TimerTask() {private int counter = 0;@Overridepublic void run() { System.out.println(counter + ":invoked!"); counter++;} }; Timer timer = new Timer(); // 过2秒钟后首次运行,以后每隔3秒运行一次 timer.schedule(task, 2000, 3000); }}
线程运行过程中的异常处理
线程的run()方法中是不允许直接抛出异常的,也就是说不能有这样的写法:run() throws Exception ,原因在于在线程的运行过程中应该最大限度地保持正常工作,因此除了一些不可预知的运行时异常,不应该主动抛出受控异常。如果非要在run()方法里处理抛出的异常,则应该定义一个实现了UncaughtExceptionHandler的类,然后指定这个类的对象在重写的uncaughtException()方法里去处理抛出的异常。另外一种方法是,将这个线程加入一个线程组,在线程组里重写uncaughtException()方法来处理抛出的异常,这时线程组的作用相当于实现了UncaughtExceptionHandler的类。
1.使用handler对象处理异常:
public class ThreadTest { public static void main(String[] args) { Thread thread = new Thread(new Runnable() {@Overridepublic void run() { throw new RuntimeException("格式错误");} }); thread.setUncaughtExceptionHandler(new MyHandler()); thread.start(); }}class MyHandler implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + ":" + e.getMessage()); }}
2.使用线程组处理异常:
public class ThreadGroupDemo { public static void main(String[] args) { ThreadGroup threadGroup1 = new ThreadGroup("group1") {public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + ": " + e.getMessage());} }; Thread thread1 = new Thread(threadGroup1, new Runnable() {public void run() { throw new RuntimeException("测试异常");} }); thread1.start(); }}