Java多线程学习笔记

来源:互联网 发布:淘宝seo怎么优化关键词 编辑:程序博客网 时间:2024/06/05 09:13

Java多线程学习笔记

1、继承Thread类

实现多线程的常用方法就是继承Thread类,然后覆盖run()方法。下面是一个通过继承Thread类实现多线程的小例子:

import java.util.Date;public class ThreadTest extends Thread{    @Override    public void run() { // 重写run方法        System.out.println(this.getName() + " " + new Date().toString());    }    public static void main(String[] args) {        // TODO Auto-generated method stub        ThreadTest t1 = new ThreadTest();        t1.start();        ThreadTest t2 = new ThreadTest();        t2.start();    }}

运行结果如下:

这里写图片描述

Thread类实际上是Runnable接口的实现,

public class Thread implements Runnable {    ...}

Thread类中,有一些方法比较常用:

  1. 线程在创建后,需要调用start()才能运行,然后线程会自动调用run()方法,所以在子类中需要覆盖run()方法。注意,我们要用start()来启动线程,run()方法仅仅是一个普通的方法。

  2. sleep()和suspend()都可以让线程暂停执行,但是二者的区别如下:
    (1).sleep()使线程休眠后,只能在时间结束后,线程才能恢复到就绪状态;而suspend()挂起线程后,可以通过resume()唤醒线程。
    (2).另外,sleep()仅对当前线程起作用,而suspend()可以挂起另一个线程。

  3. yield()是一个静态的native方法,它的作用是“告诉当前正在执行的线程,把运行机会交给线程池中拥有相同优先级的线程”,说白了就是把机会留给别人。

  4. stop()和interrupt()都可以中断线程,但二者区别在于stop强制终止线程,而interrupt()中断线程。关于二者的具体介绍,详见:http://blog.csdn.net/wxwzy738/article/details/8516253。这里插一句,如果我们要中断线程,最好设置一个共享变量,然后在run方法中,周期性地检查该变量的值,满足终止条件时再终止线程。

为了加深理解,现附上线程生命周期图(图片来自百度百科):

这里写图片描述

2、实现Runnable接口

Runnable接口的源码如下,只有一个抽象方法run(),因此实现这个接口的核心就是覆盖run()方法。

public interface Runnable {    public abstract void run();}

下面是一个小例子,这个例子实现了Runnable接口

import java.util.Date;public class ThreadTest implements Runnable{    String name;    ThreadTest(String name) {        this.name = name;    }    @Override    public void run() {        System.out.println(this.name + " " + new Date().toString());    }    public static void main(String[] args) {        // TODO Auto-generated method stub        ThreadTest t1 = new ThreadTest("Thread1");        new Thread(t1).start();        ThreadTest t2 = new ThreadTest("Thread2");        new Thread(t2).start();    }}

运行结果如下:

这里写图片描述

3、join方法

无join()时,主线程调用start()后,程序立即返回到主线程,此时主线程和子线程各运行各的,也就是我们常说的“异步”。

有join()时,主线程调用start()后,会一直等待子线程执行完毕,再往下执行,这也就是“同步”。

下面看两个小例子:

import java.util.Date;public class ThreadTest extends Thread{    @Override    public void run() {        while(true){            try {                this.sleep(1000);                System.out.println(this.getName() + " " + new Date().toString());            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }           }    }    public static void main(String[] args) {        // TODO Auto-generated method stub        ThreadTest t1 = new ThreadTest();        t1.start();                ThreadTest t2 = new ThreadTest();        t2.start();        // 没有join() 直接返回到主线程        System.out.println("t1,t2 stop");    }}

运行结果显示,主线程在启动t1、t2两个子线程后,直接返回到主线程继续执行 System.out.println(“t1,t2
stop”);

这里写图片描述

下面我们加上join()方法,同时把while去掉,避免程序进入死循环无法返回。

import java.util.Date;public class ThreadTest extends Thread{    @Override    public void run() {        // 去掉了while(true)的循环        try {            this.sleep(1000);            System.out.println(this.getName() + " " + new Date().toString());        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }       }    public static void main(String[] args) throws InterruptedException { // 注意要抛出异常        // TODO Auto-generated method stub        ThreadTest t1 = new ThreadTest();        t1.start();                ThreadTest t2 = new ThreadTest();        t2.start();        t1.join(); // t1添加join()        t2.join(); // t2添加join()        System.out.println("t1,t2 stop");    }}

来看看效果吧,可以看到,程序直到t1、t2线程结束后,才返回执行System.out.println(“t1,t2 stop”);

这里写图片描述

4、synchronized关键字

synchronized知识点总结:

1、synchronized可以修饰代码块、对象和方法,不能用于修饰int、char、boolean等简单类型的变量。

synchronized int a = 0; // 错误,synchronized 不能修饰int类型变量

2、synchronized不能被继承。若父类中有一个方法使用了synchronized修饰,子类中覆盖了这个方法,子类中的这个方法默认不是同步的,必须加synchronized关键词显示地生命同步。

3、synchronized不能放在返回类型后面,比如下面这句代码就是错误的。

void synchronized func() // 错的,synchronized不能放在返回值后面

synchronized关键字可以修饰代码块:

class Test {    private final static String key = ""; // 注意要设置为final    synchronized(key) {        // TODO 这里是同步的代码块        // 注意,这里不能改变key的值,否则不能同步        // 因此要把key设置为final    }}

synchronized关键字也可以用来修饰方法,请看下面的例子:在单件模式中使用synchronized关键字。

5、用synchronized关键字实现单件模式

class Singleton {    private static Singleton instance;    private Singleton() {    }    // 使用synchronized 关键字修饰方法    public static synchronized Singleton getInstance() {        if(instance == null) {            instance = new Singleton();        }        return instance;    }}

当然,单件模式还有更简单的实现方式:

public class Singleton {    private final static Singleton instance = new Singleton(); // 使用“急切”    private Singleton() {    }    public static Singleton getInstance() {         return instance;    }}

6、实例:使用多线程打印数字

public class ThreadTest implements Runnable {    private int num = 0;    @Override    public synchronized void run() {        for(int i = 0; i < 10; i++) {            System.out.println(this.num);            num++;        }    }    public static void main(String[] args) {        // TODO Auto-generated method stub        ThreadTest t1 = new ThreadTest();        new Thread(t1).start(); // 打印0-9        new Thread(t1).start(); // 打印10-19        new Thread(t1).start(); // 打印20-29    }}

程序的运行结果如下:

这里写图片描述

今天就到这里,拜~

这里写图片描述

原创粉丝点击