Java多线程:Java多线程基础

感性地理解一下什么是线程?java

线程这个概念实际上是比较抽象的,虽然依照教科书上的说法:多线程

进程是从系统获取资源的最小单位,线程是程序执行的最小单位。程序是静态存在于磁盘上的一段文本,进程运行这段文本记录的命令。ide

也就是说,进程从系统那里获取到了必定的CPU占用时间片、内存单元和IO等等资源,而后线程将这些资源利用起来执行程序,线程执行程序是什么意思呢?就是把程序记录的那些命令逐条依序一步步在CPU上运做,数据在内存、IO上流转,将命令执行完。
这个层级的概念存在于OS上,OS的调度抽象层级并非那么直观,若是咱们在说明白一点,在作底层的计算机组成原理实验的时候,在咱们接好连线后硬件就具备了处理数据的能力,只要扳动不一样的开关就能够将数据读写在不一样的芯片上,咱们的程序也许是为了完成数据流转写在纸上的扳动不一样开关的序列,因此程序是属于IO级别的,而后咱们依照纸上的命令序列实际上手去扳动不一样的开关执行的就是这段程序,因此咱们本身充当的角色就是进程,最终就得出了这样的结论:进程“执行”程序。至于线程呢,能够看做是进程在执行过程当中的策略,好比说在一我的扳动开关的时候就是单进程单线程,若是是两我的扳动开关就是单进程多线程,若是两我的能配合起来扳动开关就是多线程同步,因此线程和进程之间并不是互斥的概念,而是相容的概念,若是有线程就必定有进程,一个进程包含了至少一个的线程。函数

建立线程的方法
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接口的执行类来建立与之对应的线程;code

public class ThreadFactoryDemo {

    public static void main(String[] args) {
        ThreadFactory factory = new ThreadFactory() {

            @Override
            public Thread newThread(Runnable r) {
                // TODO Auto-generated method stub
                return new Thread(r);
            }
        };
        factory.newThread(new Runnable() {

            @Override
            public void run() {
                System.out.println("in runnable.");

            }
        }).start();
    }

}

注意:只有调用Thread类的Start方法,才能真正地在一个独立的线程中执行代码,直接调用Thread类的run方法,并不能启动一个新的线程,代码是在调用者线程中执行的。对象

那么主线程的run()方法在哪里呢?任何java程序的main执行入口担当着启动主线程的做用,只要进入了main函数就执行了主线程,所以整个main函数里的内容就是主线程的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() {

            @Override
            public void run() {
                System.out.println("Runnable.run()");

            }
        }) {
            @Override
            public 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() {
            @Override
            public 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;

            @Override
            public 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() {
            @Override
            public 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();
    }
}
相关文章
相关标签/搜索